Spring注解(@Bean歇父、@ComponentScan、自定義TypeFilter)

環(huán)境搭建

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.spring.test</groupId>
    <artifactId>spring-annotation</artifactId>
    <version>1.0-SNAPSHOT</version>
    
    <dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.12.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>4.3.12.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.3.12.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.1.2</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.44</version>
    </dependency>
    </dependencies>

</project>

bean

package com.ming.beans;

public class Person {
     private String name;
    private int age;
    public Person() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

編寫配置類
給容器中注冊了一個bean再愈,類型為返回值類型榜苫,id 默認使用方法名為id

@Configuration
public class MainConfig {
    /**
     * 給容器中注冊了一個bean,類型為返回值類型翎冲,id 默認使用方法名為id
     * @return
     *
     * 修改bean的名字
     * 1.修改方法名
     * 2.在@Bean 注解中指定名字  @Bean("person02")
     */
    @Bean("person02")
    public Person person(){
        return new Person("10", 20);
    }
}

Spring 使用xml 注入bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <bean id="person" class="com.spring.annotation.bean.Person">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="20"></property>
    </bean>
</beans>

測試代碼

public class MainTest {
    public static void main(String[] args){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        Person bean = applicationContext.getBean(Person.class);
        System.out.println(bean);

        /**
         * 按照類型獲取bean的名字(默認注入bean的方法名字)
         */
        String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);

        for (String s : beanNamesForType) {
            System.out.println(s);
        }
    }
}

運行結(jié)果

Person [name=10, age=20, nickName=null]
person02
Process finished with exit code 0 

而在實際開發(fā)中會經(jīng)常使用包掃描,只要標注了@Controller垂睬、@Service、@Repository抗悍,@Component 注解的類會自動加入到容器中

Spring xml 包掃描

<context:component-scan base-package="com.ming" use-default-filters="false"></context:component-scan>

Spring使用注解 包掃描 @ComponentScan

@ComponentScan("com.spring.annotation")
@Configuration
public class MainConfig {
    /**
     * 給容器中注冊了一個bean驹饺,類型為返回值類型,id 默認使用方法名為id
     * @return
     *
     * 修改bean的名字
     * 1.修改方法名
     * 2.在@Bean 注解中指定名字  @Bean("person02")
     */
    @Bean("person02")
    public Person person(){
        return new Person("10", 20);
    }
}

1.添加bean

@Controller
public class BookController {
}
@Repository
public class BookDao {

}
@Service
public class BookService {
}

2.測試

@Test
    public void test(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        /**
         * 獲取容器中所有bean定義的名字
         */
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }

3.測試結(jié)果

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
bookDao
bookService
person02

Process finished with exit code 0

注意:mainConfig 配置類也是一個組件 因為@Configuration 注解中標有@Component

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    String value() default "";
}

@ComponentScan 包含過濾和排除過濾
ComponentScan.Filter[] includeFilters() default {}; 按照某些規(guī)則排除組件
ComponentScan.Filter[] excludeFilters() default {}; 指定掃描的時候只需要包含哪些組件

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

    String resourcePattern() default "**/*.class";
    /**/
    boolean useDefaultFilters() default true;

    ComponentScan.Filter[] includeFilters() default {};

    ComponentScan.Filter[] excludeFilters() default {};

    boolean lazyInit() default false;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        FilterType type() default FilterType.ANNOTATION;

        @AliasFor("classes")
        Class<?>[] value() default {};

        @AliasFor("value")
        Class<?>[] classes() default {};

        String[] pattern() default {};
    }
}

FilterType 指定不同的包含/排除 規(guī)則

package org.springframework.context.annotation;

public enum FilterType {
    ANNOTATION,
    ASSIGNABLE_TYPE,
    ASPECTJ,
    REGEX,
    CUSTOM;

    private FilterType() {
    }
}

例如:我們按照注解類型排除 Controller.class, Service.class, Repository.class

@ComponentScan(value = "com.spring.annotation", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class, Repository.class})
})
@Configuration
public class MainConfig {
    /**
     * 給容器中注冊了一個bean缴渊,類型為返回值類型赏壹,id 默認使用方法名為id
     * @return
     *
     * 修改bean的名字
     * 1.修改方法名
     * 2.在@Bean 注解中指定名字  @Bean("person02")
     */
    @Bean("person02")
    public Person person(){
        return new Person("10", 20);
    }
}

測試結(jié)果(容器中已經(jīng)沒有 BookController BookService BookServie這三個bean)

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
person02

Process finished with exit code 0

包含過濾 includeFilters 如果想要只包含 Controller 注解的bean,如下配置

注意:需要添加 useDefaultFilters = false

@ComponentScan(value = "com.spring.annotation", includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,
                classes = {Controller.class})},useDefaultFilters = false)
@Configuration
public class MainConfig {
    /**
     * 給容器中注冊了一個bean衔沼,類型為返回值類型蝌借,id 默認使用方法名為id
     * @return
     *
     * 修改bean的名字
     * 1.修改方法名
     * 2.在@Bean 注解中指定名字  @Bean("person02")
     */
    @Bean("person02")
    public Person person(){
        return new Person("10", 20);
    }
}

對比Spring xml 配置

 <context:component-scan base-package="com.test.ming" use-default-filters="false"></context:componentscan>

單元測試

@Test
    public void test(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        /**
         * 獲取容器中所有bean定義的名字
         */
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }

結(jié)果如下(可以看到只有Controller注解的bean在容器中)

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
person02

Process finished with exit code 0

我們還可以使用@ComponentScans 來指定 掃描策略
ComponentScans 注解結(jié)構(gòu) 如下

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface ComponentScans {
    ComponentScan[] value();
}

可以看到其內(nèi)部是一個ComponentScan[] 數(shù)組,所以我們可以在其中指定多個ComponentScan

@ComponentScans(value = {

        @ComponentScan(value = "com.spring.annotation", includeFilters = {
                @ComponentScan.Filter(type = FilterType.ANNOTATION,
                        classes = {Controller.class})},useDefaultFilters = false)

})
@Configuration
public class MainConfig {
    /**
     * 給容器中注冊了一個bean,類型為返回值類型指蚁,id 默認使用方法名為id
     * @return
     *
     * 修改bean的名字
     * 1.修改方法名
     * 2.在@Bean 注解中指定名字  @Bean("person02")
     */
    @Bean("person02")
    public Person person(){
        return new Person("10", 20);
    }
}

FilterType.ASSIGNABLE_TYPE 指定不同的類型
例如菩佑,包含Controller 注解的bean 和 BookService類型的bean

@ComponentScans(value = {

        @ComponentScan(value = "com.spring.annotation", includeFilters = {
                @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class})
                
        },useDefaultFilters = false)
})
@Configuration
public class MainConfig {
    /**
     * 給容器中注冊了一個bean,類型為返回值類型凝化,id 默認使用方法名為id
     * @return
     *
     * 修改bean的名字
     * 1.修改方法名
     * 2.在@Bean 注解中指定名字  @Bean("person02")
     */
    @Bean("person02")
    public Person person(){
        return new Person("10", 20);
    }
}

FilterType.CUSTOM:使用自定義規(guī)則
1.編寫MyTypeFilter 并實現(xiàn) TypeFilter 接口
2.match方法中 實現(xiàn)自定義規(guī)則

/**
 * 自定義過濾規(guī)則
 */
public class MyTypeFilter implements TypeFilter {

    /**
     *
     * @param metadataReader
     * @param metadataReaderFactory
     * @return
     * @throws IOException
     * metadataReader:讀取到的當前正在掃描的類的信息
     * metadataReaderFactory:可以獲取到其他任何類信息的
     *
     *
     */

    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {

        // TODO Auto-generated method stub
        //獲取當前類注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //獲取當前正在掃描的類的類信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //獲取當前類資源(類的路徑)
        Resource resource = metadataReader.getResource();

        String className = classMetadata.getClassName();
        System.out.println("--->"+className);
        if(className.contains("er")){
            return true;
        }
        return false;
    }
}

3.使用實例(當前掃描到的類稍坯,類名中包含er,就會注入到容器中)

@ComponentScans(value = {

        @ComponentScan(value = "com.spring.annotation", includeFilters = {
                @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class}),
                @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})

        },useDefaultFilters = false)
})
@Configuration
public class MainConfig {
    /**
     * 給容器中注冊了一個bean搓劫,類型為返回值類型劣光,id 默認使用方法名為id
     * @return
     *
     * 修改bean的名字
     * 1.修改方法名
     * 2.在@Bean 注解中指定名字  @Bean("person02")
     */
    @Bean("person02")
    public Person person(){
        return new Person("10", 20);
    }
}

小總結(jié):
@ComponentScan value:指定要掃描的包
excludeFilters = Filter[] :指定掃描的時候按照什么規(guī)則排除那些組件
includeFilters = Filter[] :指定掃描的時候只需要包含哪些組件
FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照給定的類型袜蚕;
FilterType.ASPECTJ:使用ASPECTJ表達式
FilterType.REGEX:使用正則指定
FilterType.CUSTOM:使用自定義規(guī)則

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市绢涡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌遣疯,老刑警劉巖雄可,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缠犀,居然都是意外死亡数苫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門辨液,熙熙樓的掌柜王于貴愁眉苦臉地迎上來虐急,“玉大人,你說我怎么就攤上這事滔迈≈褂酰” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵燎悍,是天一觀的道長敬惦。 經(jīng)常有香客問我,道長谈山,這世上最難降的妖魔是什么俄删? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮奏路,結(jié)果婚禮上畴椰,老公的妹妹穿的比我還像新娘。我一直安慰自己鸽粉,他們只是感情好斜脂,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著潜叛,像睡著了一般秽褒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上威兜,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天销斟,我揣著相機與錄音,去河邊找鬼椒舵。 笑死蚂踊,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的笔宿。 我是一名探鬼主播犁钟,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼棱诱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了涝动?” 一聲冷哼從身側(cè)響起迈勋,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎醋粟,沒想到半個月后靡菇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡米愿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年厦凤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片育苟。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡较鼓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出违柏,到底是詐尸還是另有隱情博烂,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布勇垛,位于F島的核電站脖母,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏闲孤。R本人自食惡果不足惜谆级,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望讼积。 院中可真熱鬧肥照,春花似錦、人聲如沸勤众。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽们颜。三九已至吕朵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間窥突,已是汗流浹背努溃。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留阻问,地道東北人梧税。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親第队。 傳聞我的和親對象是個殘疾皇子哮塞,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容