• Spring:注解组件注册


    @Configuration&@Bean

        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>4.3.12.RELEASE</version>
        </dependency>
    
    @Configuration
    public class MainConfig {
        @Bean
        public Person person(){
            return new Person("aaa",19);
        }
    }
    
    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);
    
            String[] names = applicationContext.getBeanNamesForType(Person.class);
            System.out.println(Arrays.toString(names));
        }
    }
    

    image-20201215170413368

    @ComponentScan自动扫描组件&指定扫描规则

    image-20201215171020541

        @Test
        public void test(){
            ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
            String[] names = applicationContext.getBeanDefinitionNames();
            for (String name : names) {
                System.out.println(name);
            }
        }
    

    image-20201215171049669

    指定排除规则:

    @ComponentScan(value = "com.wj", excludeFilters = {
            //按照注解类型去排除(排除标注Controller和Repository的类)
            @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class,Repository.class})
    })
    
    @ComponentScan(value = "com.wj", includeFilters = {
            //按照注解类型去扫描(只扫描标注Controller和Repository的类)
            @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class,Repository.class})
    },useDefaultFilters=false)
    

    多组规则:

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

    此外,ComponentScan是一个可重复注解(jdk8),这也就意味着可以在一个类上可以标注多个ComponentScan来制定多组规则

    TypeFilter指定过滤规则

    按照指定的类型

    public enum FilterType {
    	//按照注解
    	ANNOTATION,
        //按照给定类型
    	ASSIGNABLE_TYPE,
        //ASPECTJ表达式
    	ASPECTJ,
        //正则指定
    	REGEX,
        //自定义规则
    	CUSTOM
    }
    

    按照指定类型去扫描

    @ComponentScan(value = "com.wj", includeFilters = {
            @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = BookService.class)
    },useDefaultFilters=false)
    

    image-20201215173807290

    自定义filter:我们需要实现TypeFilter接口

    	/** Filter candidates using a given custom
    	 * {@link org.springframework.core.type.filter.TypeFilter} implementation.
    	 */
    	CUSTOM
    
    
    public class MyTypeFilter implements TypeFilter {
    
        /**
         *
         * @param metadataReader 读取到当前正在扫描的类的信息
         * @param 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-->"+className);
            return false;
        }
    }
    
    @ComponentScan(value = "com.wj", includeFilters = {
            @ComponentScan.Filter(type = FilterType.CUSTOM, classes = MyTypeFilter.class)
    },useDefaultFilters=false)
    
    image-20201215175419347

    组件设置作用域@Scope

    一般来说,放入IOC容器的bean都是单实例的

    	/**
    	 * Specifies the name of the scope to use for the annotated component/bean.
    	 * <p>Defaults to an empty string ({@code ""}) which implies
    	 * {@link ConfigurableBeanFactory#SCOPE_SINGLETON SCOPE_SINGLETON}.
    	 * @since 4.2
    	 * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE 多实例的
    	 * @see ConfigurableBeanFactory#SCOPE_SINGLETON 单实例的
    	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST 同一次请求创建一个实例
    	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION 同一个Session创建一个实例
    	 * @see #value
    	 */
    

    单实例:ioc容器启动会调用方法创建对象放到ioc容器中,以后每次获取就是直接从容器中获取。

    多实例:ioc容器启动并不会去调用方法创建对象放在容器中,每次获取的时候才会调用方法创建对象。

    @Lazy懒加载

    因为单实例对象默认在容器启动的时候创建对象。

    使用@Lazy懒加载会在容器启动的时候不创建对象,需要使用的时候再创建对象

        @Bean
        @Lazy
        public Person person(){
            System.out.println("person实例创建了。。。。");
            return new Person("aaa",19);
        }
    

    @Conditional按照条件注册

    按照一定的条件进行判断,满足条件才注册bean。

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    //该注解可以加在类上和方法上
    public @interface Conditional {
    
    	/**
    	 * All {@link Condition}s that must {@linkplain Condition#matches match}
    	 * in order for the component to be registered.
    	 */
    	Class<? extends Condition>[] value();
    
    }
    
        @Bean("bbb")
        @Conditional(WindowsCondition.class)
        public Person person01(){
            return new Person("bbb",20);
        }
    
        @Bean("ccc")
        @Conditional(LinuxCondition.class)
        public Person person02(){
            return new Person("ccc",21);
        }
    
    public class LinuxCondition implements Condition  {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Environment environment = context.getEnvironment();
            String property = environment.getProperty("os.name");
            return property.contains("linux");
        }
    }
    
    public class WindowsCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Environment environment = context.getEnvironment();
            String property = environment.getProperty("os.name");
            return property.contains("Windows");
        }
    }
    

    我目前使用的是windows,进行测试:

        @Test
        public void test02(){
            String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
            for (String s : beanNamesForType) {
                System.out.println(s);
            }
        }
    

    image-20201216093417844

    @Import导入组件

    @Configuration
    //向IOC容器中导入Color组件,bean的id默认是组件的全类名
    @Import(Color.class)
    public class MainConfig2 {
    }
    
        @Test
        public void testImport(){
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
            Color bean = context.getBean(Color.class);
            System.out.println(bean);
        }
    

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

    测试:

    //自定义逻辑返回需要导入的组件
    public class MyImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    
            return new String[]{"com.wj.bean.Red","com.wj.bean.Person"};
        }
    }
    
    @Configuration
    @Import({Color.class, MyImportSelector.class})//向IOC容器中导入Color组件
    public class MainConfig2 {
    }
    

    测试方法:

        @Test
        public void testImport(){
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
            printBean(context);
        }
    
        public void printBean(ApplicationContext applicationContext){
            String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
            for (String beanDefinitionName : beanDefinitionNames) {
                System.out.println(beanDefinitionName);
            }
        }
    

    image-20201216095730216

    使用ImportBeanDefinitionRegistrar

    手动注册bean到容器中

    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
    	 */
        //AnnotationMetadata 当前类的注解信息
        //BeanDefinitionRegistry BeanDefinitionRegistry注册类
    	public void registerBeanDefinitions(
    			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
    
    }
    
    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        //如果容器中含有Red和Person,就往容器中导入blue
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            boolean red = registry.containsBeanDefinition("com.wj.bean.Red");
            boolean person = registry.containsBeanDefinition("com.wj.bean.Person");
            if(red && person){
                //指定bean的定义信息
                RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Blue.class);
                registry.registerBeanDefinition("blue",rootBeanDefinition);
            }
        }
    }
    
    @Configuration
    @Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})//向IOC容器中导入Color组件
    public class MainConfig2 {
    }
    
        @Test
        public void testImport(){
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
            printBean(context);
        }
    

    执行结果:

    image-20201216100730266

    FactoryBean注册组件

    //创建一个spring定义的FactoryBean
    public class ColorFactoryBean implements FactoryBean<Color> {
        @Override
        public Color getObject() throws Exception {
            System.out.println("ColorFactoryBean初始化。。。");
            return new Color();
        }
    
        @Override
        public Class<?> getObjectType() {
            return Color.class;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    
    @Configuration
    @Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})//向IOC容器中导入Color组件
    public class MainConfig2 {
    
        @Bean
        public ColorFactoryBean colorFactoryBean(){
            return new ColorFactoryBean();
        }
    }
    
        @Test
        public void testImport() throws Exception {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
            Object bean = context.getBean("colorFactoryBean");
            System.out.println(bean);
    
            Object bean2 = context.getBean("&colorFactoryBean");
            System.out.println(bean2);
        }
    

    image-20201216102833960

    在id前面加一个&符号,可以直接获取FactoryBean本身。这里在BeanFactory的源码中提到:

    public interface BeanFactory {
    
    	/**
    	 * Used to dereference a {@link FactoryBean} instance and distinguish it from
    	 * beans <i>created</i> by the FactoryBean. For example, if the bean named
    	 * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
    	 * will return the factory, not the instance returned by the factory.
    	 */
    	String FACTORY_BEAN_PREFIX = "&";
    
  • 相关阅读:
    MD5算法--网盘秒传
    无线网络定位算法综述
    android学习---异步任务(AsyncTask)
    python中局部变量的定义
    python3里函数怎么样使用元组或字典作为参数调用(复制他人博客)
    调试exynos4412—ARM嵌入式Linux—LEDS/GPIO驱动之一
    Linux入门之——安装虚拟机软件
    Linux学习方法之以始为终—Linux工作分类
    Linux基础系列—Linux内核源码目录结构
    Linux基础系列—Linux体系结构和Linux内核结构
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/14142725.html
Copyright © 2020-2023  润新知