美文网首页
Spring注解(@Bean、@ComponentScan、自定

Spring注解(@Bean、@ComponentScan、自定

作者: Godlike_4029 | 来源:发表于2019-03-21 02:28 被阅读0次

    环境搭建

    <?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);
            }
        }
    }
    

    运行结果

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

    而在实际开发中会经常使用包扫描,只要标注了@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.测试结果

    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 {}; 按照某些规则排除组件
    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 指定不同的包含/排除 规则

    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);
        }
    }
    

    测试结果(容器中已经没有 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);
            }
        }
    

    结果如下(可以看到只有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 注解结构 如下

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

    可以看到其内部是一个ComponentScan[] 数组,所以我们可以在其中指定多个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:使用自定义规则
    1.编写MyTypeFilter 并实现 TypeFilter 接口
    2.match方法中 实现自定义规则

    /**
     * 自定义过滤规则
     */
    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);
        }
    }
    

    小总结:
    @ComponentScan value:指定要扫描的包
    excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
    includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
    FilterType.ANNOTATION:按照注解
    FilterType.ASSIGNABLE_TYPE:按照给定的类型;
    FilterType.ASPECTJ:使用ASPECTJ表达式
    FilterType.REGEX:使用正则指定
    FilterType.CUSTOM:使用自定义规则

    相关文章

      网友评论

          本文标题:Spring注解(@Bean、@ComponentScan、自定

          本文链接:https://www.haomeiwen.com/subject/zwfamqtx.html