• Spring学习一、组件注册


    Spring 组件注册的方式

    1.XML-based metadata

    1.1 XML Configuration

    services.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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- services -->
        <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
            <property name="accountDao" ref="accountDao"/>
            <property name="itemDao" ref="itemDao"/>
            <!-- additional collaborators and configuration for this bean go here -->
        </bean>
    
        <!-- more bean definitions for services go here -->
    
    </beans>
    

    The id attribute is a string that identifies the individual bean definition.

    The class attribute defines the type of the bean and uses the fully qualified classname.

    daos.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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="accountDao"
            class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
            <!-- additional collaborators and configuration for this bean go here -->
        </bean>
    
        <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
            <!-- additional collaborators and configuration for this bean go here -->
        </bean>
    
        <!-- more bean definitions for data access objects go here -->
    
    </beans>
    

    1.2 Using the Container

    // create and configure beans
    ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
    
    // retrieve configured instance
    PetStoreService service = context.getBean("petStore", PetStoreService.class);
    
    // use configured instance
    List<String> userList = service.getUsernameList();
    

    2.Annotation-based Configuration

    Spring 2.5 introduced support for annotaion-based configruation metadata.

    XML-based configuration metadata configures these beans as elements inside a top-level element. Java configuration typically uses @Bean - annotated methods with a Configuration classs.

    2.1 Use Configuration Annotated

     @Configuration
     public class AppConfig {
    
         @Bean
         public MyBean myBean() {
             // instantiate, configure and return bean ...
         }
     }
    

    2.2 Bootstrapping @Configuration classes

    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.register(AppConfig.class);
    ctx.refresh();
    MyBean myBean = ctx.getBean(MyBean.class);
    

    2.3 使用CompentScan 扫描

    	/**
    	 * Alias for {@link #basePackages}.
    	 * <p>Allows for more concise annotation declarations if no other attributes
    	 * are needed &mdash; for example, {@code @ComponentScan("org.my.pkg")}
    	 * instead of {@code @ComponentScan(basePackages = "org.my.pkg")}.
    	 */
    	@AliasFor("basePackages")
    	String[] value() default {};
    

    上面是@CompentScan源码中的value说明,如果给默认值,就相当于扫描basePackages.

    @ComponentScan(
            // 配置扫描包的根路径
            value = {"com.zuoyan"}
    )
    

    2.4 @compentScan 配置过滤扫描

    	/**
    	 * Specifies which types are not eligible for component scanning.
    	   指定那些类型不适合进行组件扫描
    	   
    	   需要指定的是一个Filter数组
    	 * @see #resourcePattern
    	 */
    	Filter[] excludeFilters() default {};
    
    	@Retention(RetentionPolicy.RUNTIME)
    	@Target({})
    	@interface Filter {
    
    		/**
    		 * The type of filter to use.
    		 * 指定FilterType 使用的类型
    		 */
    		FilterType type() default FilterType.ANNOTATION;
    
    		/**
    		 * Alias for {@link #classes}.
    		 * @see #classes
    		 */
    		@AliasFor("classes")
    		Class<?>[] value() default {};
    
    		
    		@AliasFor("value")
    		Class<?>[] classes() default {};
    
    		
    		String[] pattern() default {};
    
    	}
    

    FilterType 类型

    public enum FilterType {
    
    	/**
    	 * Filter candidates marked with a given annotation.
    	 * @see org.springframework.core.type.filter.AnnotationTypeFilter
    	 */
    	ANNOTATION,
    
    	/**
    	 * Filter candidates assignable to a given type.
    	 * @see org.springframework.core.type.filter.AssignableTypeFilter
    	 */
    	ASSIGNABLE_TYPE,
    
    	/**
    	 * Filter candidates matching a given AspectJ type pattern expression.
    	 * @see org.springframework.core.type.filter.AspectJTypeFilter
    	 */
    	ASPECTJ,
    
    	/**
    	 * Filter candidates matching a given regex pattern.
    	 * @see org.springframework.core.type.filter.RegexPatternTypeFilter
    	 */
    	REGEX,
    
    	/** Filter candidates using a given custom
    	 * {@link org.springframework.core.type.filter.TypeFilter} implementation.
    	 */
    	CUSTOM
    
    }
    

    使用过滤

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.FilterType;
    import org.springframework.context.annotation.ComponentScan.Filter;
    import org.springframework.context.annotation.ComponentScans;
    
    import com.atguigu.bean.Person;
    
    //配置类==配置文件
    @Configuration  //告诉Spring这是一个配置类
    
    @ComponentScans(
    		value = {
    				@ComponentScan(value="com.atguigu",includeFilters = 
                                   {
    						/*						
    						@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
    						@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),
    						*/
    						@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
    							},
                        useDefaultFilters = false)
    				}
    		)
    //@ComponentScan  value:指定要扫描的包
    //excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
    //includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
    //FilterType.ANNOTATION:按照注解
    //FilterType.ASSIGNABLE_TYPE:按照给定的类型;
    //FilterType.ASPECTJ:使用ASPECTJ表达式
    //FilterType.REGEX:使用正则指定
    //FilterType.CUSTOM:使用自定义规则
    public class MainConfig {
    	
    	//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
    	@Bean("person")
    	public Person person01(){
    		return new Person("lisi", 20);
    	}
    
    }
    

    2.5 @Scope 配置Bean的作用域

    @Configuration
    public class StudentBeanConfiguration {
    
        @Scope("prototype")
        @Bean
        Student student(){
            return new Student(10001L, "zuoyan");
        }
    }
    
      @Test
        public void testBeanScope(){
    
            Student stu1 = (Student) applicationContext.getBean("student");
            Student stu2 = (Student) applicationContext.getBean("student");
            System.out.println(stu1 == stu2);
        }
    

    输出结果

    Spring Contation Initializer Ok ... 
    Student Construct is exec ... 
    Student Construct is exec ... 
    false
    

    可以看到创建了两次对象,而且两个对象不相等,因为这个是使用的多例的Bean作用域

    更改bean的作用域

    @Scope("singleton")
    

    还是上面的代码查看控制台输出结果

    Student Construct is exec ... 
    Spring Contation Initializer Ok ... 
    true
    

    2.6 @Lazy 配置懒加载

    @Configuration
    public class StudentBeanConfiguration {
    
        @Scope("singleton")
        @Lazy
        @Bean
        Student student(){
            return new Student(10001L, "zuoyan");
        }
    }
    

    控制台输出内容

    Spring Contation Initializer Ok ... 
    Student Construct is exec ... 
    true
    

    可以通过和上面的控制台输出内容进行对比,发现Student的构造函数打印在 Spring Container 初始化完成之后调用的,这说明 Bean是在我们需要使用的时候才执行从初始化的。

    2.7 @Conditional 条件配置

    It is often useful to conditionally enable or disable a complete @Configuration class or even individual @Bean methods, based on some arbitrary system state. One common example of this is to use the @Profile annotation to activate beans only when a specific profile has been enabled in the Spring Environment (see Bean Definition Profiles for details).

    大意就是条件注解对一个类或者独立的Bean注册方法的启用或者禁用非常有帮助,一个最常见的例子就是使用@Profile注解指定一个特定的配置文件来激活Bean

    在需要添加的配置类上添加条件注解,控制粒度可以具体到某个方法上

    @Conditional({SystemOSCondition.class})
    @Configuration
    public class StudentBeanConfiguration {
    
        @Scope("singleton")
        @Lazy
        @Bean
        Student student(){
            return new Student(10001L, "zuoyan");
        }
    
    
        @Bean
        Student windows(){
            return new Student(00001L, "Windows");
        }
        
        @Bean
        Student linux(){
            return new Student(00002L, "Windows");
        }
    }
    

    需要自己实现Spring-Framework 中的Condition接口

    /**
     * @Author: ZuoYanCoder
     * @Description: 实现自定义的条件
     * @Date: 2020/4/17 10:50
     * @Version: 1.0
     */
    public class SystemOSCondition implements Condition {
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    
            Environment environment = context.getEnvironment();
            String systemOsNanme = environment.getProperty("os.name");
            System.out.println(systemOsNanme);
            return systemOsNanme.contains("Windows");
        }
    }
    

    测试方法代码类

    @Test
        public void testConditionalAnnotated(){
    
            String[] beanNamesForType = applicationContext.getBeanNamesForType(Student.class);
    
            for (String name:beanNamesForType) {
                System.out.println(name);
            }
    
            Map<String, Student> studentMap = applicationContext.getBeansOfType(Student.class);
    
            System.out.println(studentMap);
        }
    

    执行测试方法打印结果

    Windows 10
    Windows 10
    Windows 10
    Student Construct is exec ... 
    Student Construct is exec ... 
    Spring Contation Initializer Ok ... 
    student
    windows
    linux
    Student Construct is exec ... 
    {student=Student{stuId=10001, name='zuoyan'}, windows=Student{stuId=1, name='Windows'}, linux=Student{stuId=2, name='Windows'}}
    

    配置IDEA 运行时环境变量

    -Dos.name=Linux
    

    然后在运行打印结果

    Linux
    Spring Contation Initializer Ok ... 
    {}
    

    2.8 @Import导入组件使用

    2.8.1@Import 导入所需组件

    首先通过代码打印输出Spring容器中有的组件

    @Test
        public void testImportAnnotation(){
    
            String[] names = applicationContext.getBeanDefinitionNames();
    
            for (String name: names) {
                System.out.println(name);
    
            }
    
        }
    

    控制台输出

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    studentBeanConfiguration
    student
    windows
    linux
    

    通过使用@Import导入需要的组件

    @Conditional({SystemOSCondition.class})
    @Configuration
    @Import({Animal.class})
    public class StudentBeanConfiguration {
    }
    

    控制台输出

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    studentBeanConfiguration
    com.zuoyan.bean.Animal
    student
    windows
    linux
    

    @Import可以导入多个类,默认的id是类的全路径

    2.8.2 ImportSelector 导入组件

    @Conditional({SystemOSCondition.class})
    @Configuration
    @Import({Animal.class, MyImportSelector.class})
    public class StudentBeanConfiguration {}
    

    MyImportSelector类的内容

    public class MyImportSelector implements ImportSelector {
    
        /**
         *  方法返回值就是类的全路径名的数组
         *
         * @param importingClassMetadata  可以获取标有Import注解类的的所有注解
         *
         * @return
         */
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    
    		// 方法可以返回空字符串数组,但是不能返回Null
            return new String[]{"com.zuoyan.bean.Cat","com.zuoyan.bean.Dog"};
        }
    }
    

    控制台打印输出

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    studentBeanConfiguration
    com.zuoyan.bean.Animal
    com.zuoyan.bean.Cat
    com.zuoyan.bean.Dog
    student
    windows
    linux
    

    可以看到需要导入的组件已经导入到容器之中了。

    2.8.3ImportBeanDefinitationRegistrar

    在配置类上添加 ImportBeanDefinitationRegistrar

    @Conditional({SystemOSCondition.class})
    @Configuration
    @Import({Animal.class, MyImportSelector.class, MyImportBeanDefinitationRegister.class})
    public class StudentBeanConfiguration {}
    

    MyImportBeanDefinitationRegister实现

    public class MyImportBeanDefinitationRegister implements ImportBeanDefinitionRegistrar {
    
        /**
         *
         * @param importingClassMetadata  当前类的所有注解信息
         * @param registry BeanDefinition注册类,把所有需要添加的组件注册到容器中
         *                 调用BeanDefinitionRegistry.registerBeanDefinition手工注册来
         *
         */
    
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                            BeanDefinitionRegistry registry) {
            boolean catFlag = registry.containsBeanDefinition("com.zuoyan.bean.Cat");
            boolean dogFlag = registry.containsBeanDefinition("com.zuoyan.bean.Dog");
    
            if(catFlag && dogFlag)
            {
    
                // 指定Bean的定义信息
                RootBeanDefinition beanDefinition = new RootBeanDefinition(Elephant.class);
                // 指定注册Bean的名称
                registry.registerBeanDefinition("Elephant",beanDefinition);
    
            }
        }
    }
    

    测试类

    
        @Test
        public void testImportAnnotation(){
    
            String[] names = applicationContext.getBeanDefinitionNames();
    
            for (String name: names) {
                System.out.println(name);
    
            }
    
        }
    
    

    控制台打印输出

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    studentBeanConfiguration
    com.zuoyan.bean.Animal
    com.zuoyan.bean.Cat
    com.zuoyan.bean.Dog
    student
    windows
    linux
    Elephant
    

    2.9 使用FactoryBean注册组件

    首先通过自己定义一个类然后实现BeanFactory的接口

    import org.springframework.beans.factory.FactoryBean;
    import org.springframework.lang.Nullable;
    
    /**
     * @Author: ZuoYanCoder
     * @Description:
     * @Date: 2020/4/23 14:17
     * @Version: 1.0
     */
    public class CarFactoryBean implements FactoryBean<JeepCar> {
    
    
        /**
         *  需要管理的对象
         * @return
         * @throws Exception
         */
        @Nullable
        public JeepCar getObject() throws Exception {
            return new JeepCar();
        }
    
        /**
         * 返回类的类型
         * @return
         */
        @Nullable
        public Class<?> getObjectType() {
            return JeepCar.class;
        }
    
        /**
         * 是否为单例模式
         * @return
         */
        public boolean isSingleton() {
            return false;
        }
    }
    

    然后在配置中将注入进去

        @Bean
        CarFactoryBean carFactoryBean(){
            return new CarFactoryBean();
        }
    

    通过测试

     /**
         * 通过对象工程类管理对象
         */
        @Test
        public void testBeanFactory(){
            Object carFactoryBean = applicationContext.getBean("carFactoryBean");
            System.out.println("获取Bean的类型是:" + carFactoryBean.getClass());
    }
    

    查看获取到的对象是

    获取Bean的类型是:class com.zuoyan.bean.JeepCar
    

    如果需要获取工厂类对象需要在前面加上 & 符号

    获取Bean的类型是:class com.zuoyan.bean.CarFactoryBean
    

    通过isSingleton() 方法可以设置放进容器的对象是单例还是多例。

  • 相关阅读:
    word文档中画垂直或水平的线条
    word文档中把几个图形组合在一起
    设计模式
    确认删除的提示的JQuery
    Incorrect column count: expected 1, actual 4 问题
    Spring MVC 中的 controller层的方法的返回值类型
    SpringBoot 项目用户登录
    使用模板异常的解决
    Redis配置到本地以及可视化工具的安装运用
    第034讲:丰富的else语句及简洁的with语句 | 课后测试题及答案
  • 原文地址:https://www.cnblogs.com/kangxinxin/p/12760661.html
Copyright © 2020-2023  润新知