zoukankan      html  css  js  c++  java
  • spring注解--组件注册

    组件注册

    1、@Configuration , @Bean

    1)xml方式

    <?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"
          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.xsd">

       <bean id="person" class="com.cuzz.bean.Person">
           <property name="name" value="cuzz"></property>
           <property name="age" value="18"></property>
       </bean>
       
    </beans>

    使用ClassPathXmlApplicationContext 来获取

    public static void main(String[] args) {
           ApplicationContext  applicationContext = new ClassPathXmlApplicationContext("bean.xml");
           // 用id获取
           Person bean = (Person) applicationContext.getBean("person");
           System.out.println(bean);
      }

    2)注解

    编写个配置类

    @Configuration // 告诉Spring这是一个配置类
    public class MainConfig {
       // 给容器中注册一个Bean,类型为返回值类型,id默认用方法名
       // 也可以指定id
       @Bean(value = "person01")
       public Person person() {
           return new Person("vhsj", 16);
      }
    }

    通过AnnotationConfigApplicationContext来获取,并获取Id

    public static void main(String[] args) {
           AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
           Person person = (Person) context.getBean(Person.class);
           System.out.println(person);

           String[] names = context.getBeanNamesForType(Person.class);
           for (String name: names) {
               System.out.println(name);
          }
      }

    输出

    Person(name=vhsj, age=16)
    person01

    2、组件注册 @ComponentScan

    1)使用xml

    只要标注了注解就能扫描到,如:@Controller,@Service,@Repository,@Component,@Configration

    <context:component-scan base-package="com.cuzz"></context:component-scan>

    2)注解

    在配置类中添加

    @Configuration // 告诉Spring这是一个配置类
    @ComponentScan(value = "com.cuzz") // 指定包
    public class MainConfig {
       
    }

    添加controller、service等

    测试

    @Test
       public void test01() {
           AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
           // 获取所有bean定义的名字
           String[] beanNames = applicationContext.getBeanDefinitionNames();
           for (String name : beanNames) {
               System.out.println(name);
          }
      }

    输出结果

    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
    person01
    可以看出添加@Controller @Service @Repository @component注解的都可以扫描到
    

     

    还可以指定添加某些类,和排除某些类,进入ComponentScan注解中有下面两个方法

    ComponentScan.Filter[] includeFilters() default {};
    ComponentScan.Filter[] excludeFilters() default {};
    
    includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
    excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
    

    配置类,排除Controller

    @Configuration // 告诉Spring这是一个配置类
    @ComponentScan(value = "com.cuzz", excludeFilters = {
            @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
    })
    public class MainConfig {
    
    }
    
    #运行测试方法,可以得出没有Controller类的
    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
    bookDao
    bookService
    person01
    

     

    3)自定义TypeFilter指定过滤规则

    FilterType.ANNOTATION:按照注解	--常用
    FilterType.ASSIGNABLE_TYPE:按照给定的类型;--常用
    FilterType.ASPECTJ:使用ASPECTJ表达式
    FilterType.REGEX:使用正则指定
    FilterType.CUSTOM:使用自定义规则
    

    新建一个MyTypeFilte类实现TypeFilter接口

    public class MyTypeFilter implements TypeFilter{
        /**
         * metadataReader:读取到的当前正在扫描的类的信息
         * metadataReaderFactory:可以获取到其他任何类信息的
         */
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
                throws IOException {
            //获取当前类注解的信息
            AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
            //获取当前正在扫描的类的类信息
            ClassMetadata classMetadata = metadataReader.getClassMetadata();
            //获取当前类资源(类的路径)
            Resource resource = metadataReader.getResource();
    
            String className = classMetadata.getClassName();
            System.out.println("--->"+className);
            // 这些类名中包含er就返回true
            if(className.contains("er")){
                return true;
            }
            return false;
        }
    }
    

    使用自定义注解记得需要关闭默认过滤器useDefaultFilters = false

    @Configuration 
    @ComponentScan(value = "com.cuzz",
            includeFilters = @ComponentScan.Filter(type = FilterType.CUSTOM,
                    classes = MyTypeFilter.class),
            useDefaultFilters = false)
    public class MainConfig {
        // 给容器中注册一个Bean,类型为返回值类型,id默认用方法名
        // 也可以指定id
        @Bean(value = "person01")
        public Person person() {
            return new Person("vhsj", 16);
        }
    }
    

    3、组件注册@Scope设置作用域

    1)Spring的bean默认:单例的;

    @Test
        public void test02() {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
            // 获取所有bean定义的名字
            String[] beanNames = applicationContext.getBeanDefinitionNames();
            for (String name : beanNames) {
                System.out.println(name);
            }
            Object bean = applicationContext.getBean("person");
            Object bean2 = applicationContext.getBean("person");
            System.out.println(bean == bean2);   // 输出true
        }
    

    2)Scope的四个范围

    ConfigurableBeanFactory#SCOPE_PROTOTYPE   // 多实例 每次获取时创建对象,不会放在ioc容器中
    ConfigurableBeanFactory#SCOPE_SINGLETON   // 单实例 ioc容器启动是创建对象,以后从容器中获取
    WebApplicationContext#SCOPE_REQUEST       // web同一次请求创建一个实例
    WebApplicationContext#SCOPE_SESSION       // web同一个session创建一个实例
    

    4、组件注册@Lazy-bean懒加载

    1)懒加载

    懒加载的是针对单实例Bean,默认是在容器启动的时创建的,我们可以设置懒加载容器启动是不创建对象,在第一次使用(获取)Bean创建对象,并初始化

    2 ) 测试

    先给添加一个@Lazy注解

    @Configuration
    public class MainConfig2 {
    
        @Lazy
        @Bean
        public Person person() {
            System.out.println("给容器中添加Person...");
            return new Person("vhuj", 25);
        }
    }
    

    编写一个测试方法

        @Test
        public void test03() {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    
            System.out.println("ioc容器创建完成...");
            Object bean = applicationContext.getBean("person");
        }
    
    

    输出

    ioc容器创建完成...
    给容器中添加Person...
    
    

    添加一个@Lazy是在第一次获取时,创建对象,以后获取就不需要创建了,直接从容器中获取,因为它是单实例

     

    5. 组件注册@Conditional按条件注册

    按照一定条件进行判断,满足条件给容器中注册Bean

    1 ) 编写自己的Condition类

    如果系统是windows,给容器中注入"bill"

    如果系统是linux,给容器中注入"linus"

    编写WindowCondition类并重写matches方法

    /**
       * @Author: cuzz
       * @Date: 2018/9/23 20:30
       * @Description: 判断是否是windows
       */
      public class WindowCondition implements Condition{
      
          /**
           * @param context 判断条件
           * @param metadata 注释信息
           * @return boolean
           */
          @Override
          public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
              Environment environment = context.getEnvironment();
              String property = environment.getProperty("os.name");
              if (property.contains("Windows")) {
                  return true;
              }
              return false;
          }
      }
    
    

    context有以下方法

      // 能获取ioc使用的beanfactory
      ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
      // 能获取到类加载器
      ClassLoader classLoader = context.getClassLoader();
      // 获取到环境变量
      Environment environment = context.getEnvironment();
      // 获取到Bean定义的注册类
      BeanDefinitionRegistry registry = context.getRegistry();
    
    

    2)配置类

    添加Bean添加Condition条件

    @Configuration
    public class MainConfig2 {
    
        @Conditional({WindowCondition.class})
        @Bean("bill")
        public Person person01() {
            return new Person("Bill Gates", 60);
        }
        @Conditional({LinuxCondition.class})
        @Bean("linux")
        public Person person02() {
            return new Person("linus", 45);
        }
    
    }
    
    

    3 ) 测试

        @Test
        public void test04() {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    
            // 获取环境变量
            ConfigurableEnvironment environment = applicationContext.getEnvironment();
            String property = environment.getProperty("os.name");
            System.out.println(property);
    
            // 获取所有bean定义的名字
            String[] beanNames = applicationContext.getBeanDefinitionNames();
            for (String name : beanNames) {
                System.out.println(name);
            }
    
            // key 是id
            Map<String, Person> map = applicationContext.getBeansOfType(Person.class);
            System.out.println(map);
        }
    
    

    发现只有“bill”这个Bean被注入

    Windows 7
    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
    mainConfig2
    bill
    {bill=Person(name=Bill Gates, age=60)}
    
    

    6. 组件注册@Improt给容器中快速导入一个组件

    1 ) @Import导入

    @Import可以导入第三方包,或则自己写的类,比较方便,Id默认为全类名

    比如我们新建一个类

    /**
     * @Author: cuzz
     * @Date: 2018/9/23 21:08
     * @Description:
     */
    public class Color {
    }
    
    

    我们只需要在配置类添加一个@Import把这个类导入

    @Import({Color.class})
    @Configuration
    public class MainConfig2 {}
    
    

    2 ) ImportSelector接口导入的选择器

    返回导入组件需要的全类名的数组

    public interface ImportSelector {
    
        /**
         * Select and return the names of which class(es) should be imported based on
         * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
         */
        String[] selectImports(AnnotationMetadata importingClassMetadata);
    
    }
    
    

    编写一个MyImportSelector类实现ImportSelector接口

    /**
     * @Author: cuzz
     * @Date: 2018/9/23 21:15
     * @Description:
     */
    public class MyImportSelector implements ImportSelector{
    
        // 返回值就导入容器组件的全类名
        // AnnotationMetadata:当前类标注的@Import注解类的所有注解信息
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[] {"com.cuzz.bean.Car"};
        }
    }
    
    

    在配置类中,通过@Import导入

    /**
     * @Author: cuzz
     * @Date: 2018/9/23 15:40
     * @Description: 配置类
     */
    @Import({Color.class, MyImportSelector.class})
    @Configuration
    public class MainConfig2 {}
    
    

    测试结果,com.cuzz.bean.Car注入了

    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
    mainConfig2
    com.cuzz.bean.Color
    com.cuzz.bean.Car
    
    

    3 ) ImportBeanDefinitionRegistrar接口选择器

    public interface ImportBeanDefinitionRegistrar {
    
        /**
         * Register bean definitions as necessary based on the given annotation metadata of
         * the importing {@code @Configuration} class.
         * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
         * registered here, due to lifecycle constraints related to {@code @Configuration}
         * class processing.
         * @param importingClassMetadata annotation metadata of the importing class
         * @param registry current bean definition registry
         */
        public void registerBeanDefinitions(
                AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
    
    }
    
    

    编写一个ImportBeanDefinitionRegistrar实现类

    /**
     * @Author: cuzz
     * @Date: 2018/9/23 21:29
     * @Description:
     */
    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        /**
         * @param importingClassMetadata 当前类的注解信息
         * @param registry 注册类
         */
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            // 查询容器
            boolean b = registry.containsBeanDefinition("com.cuzz.bean.Car");
            // 如果有car, 注册一个汽油类
            if (b == true) {
                // 需要添加一个bean的定义信息
                RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Petrol.class);
                // 注册一个bean, 指定bean名
                registry.registerBeanDefinition("petrol", rootBeanDefinition);
            }
    
        }
    }
    
    

    配置类

    /**
     * @Author: cuzz
     * @Date: 2018/9/23 15:40
     * @Description: 配置类
     */
    @Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
    @Configuration
    public class MainConfig2 {}
    
    

    测试结果,出现了petrol

    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
    mainConfig2
    com.cuzz.bean.Color
    com.cuzz.bean.Car 
    petrol
    

    7. 组件注册使用FactoryBean注册组件

    编写一个ColorFactoryBean类

    /**
     * @Author: cuzz
     * @Date: 2018/9/23 21:55
     * @Description: Spring定义的工厂Bean
     */
    public class ColorFactoryBean implements FactoryBean<Color> {
        // 返回一个Color对象
        @Override
        public Color getObject() throws Exception {
            return new Color();
        }
    
        @Override
        public Class<?> getObjectType() {
            return Color.class;
        }
        // 是否为单例
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    
    

    注入到容器中

        @Bean
        public ColorFactoryBean colorFactoryBean() {
            return new ColorFactoryBean();
        }
    
    

    测试

        @Test
       public void test05() {
           AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);

           Object bean = applicationContext.getBean("colorFactoryBean");
           // 工厂bean调用的是getClass()方法
           System.out.println("colorFactoryBean的类型是: " + bean.getClass());
      }

    输出,发现此时的bean调用的方法是getObjectType方法

    colorFactoryBean的类型是: class com.cuzz.bean.Color

    如果需要获取BeanFactory本身,可以在id前面加一个“&”标识

        @Test
       public void test05() {
           AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);

           Object bean = applicationContext.getBean("colorFactoryBean");
           // 工厂bean调用的是getClass()方法
           System.out.println("colorFactoryBean的类型是: " + bean.getClass());
           Object bean2 = applicationContext.getBean("&colorFactoryBean");
           // 工厂bean调用的是getClass()方法
           System.out.println("colorFactoryBean的类型是: " + bean2.getClass());
      }

    此时输出

    colorFactoryBean的类型是: class com.cuzz.bean.Color
    colorFactoryBean的类型是: class com.cuzz.bean.ColorFactoryBean
  • 相关阅读:
    [GO] go使用etcd和watch方法进行实时的配置变更
    [GO]go context的deadline方法
    [GO]go使用contextCancel
    [GO]go使用etcd
    js控制复选框checkbox 只能单选
    JQuery.Ajax之错误调试帮助信息
    SQLServer2005创建定时作业任务
    JS/JQuery针对不同类型元素的操作(radio、select、checkbox)
    SQL Server跨库查询
    javax.net.ssl.SSLHandshakeException(Cas导入证书)
  • 原文地址:https://www.cnblogs.com/Nilker/p/10302179.html
Copyright © 2011-2022 走看看