• Spring注解开发系列Ⅰ--- 组件注册(上)


    统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop、事物,这么做有两个缺点:
    1、如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大;如果按需求分开.xml文件,那么.xml文件又会非常多。总之这将导致配置文件的可读性与可维护性变得很低。
    2、在开发中在.java文件和.xml文件之间不断切换,是一件麻烦的事,同时这种思维上的不连贯也会降低开发的效率。
    为了解决这两个问题,Spring引入了注解,通过"@XXX"的方式,让注解与Java Bean紧密结合,既大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性。

    1.@Configuration&@Bean给容器中注册组件

    @Configuration可理解为用spring的时候xml里面的<beans>标签

    @Bean可理解为用spring的时候xml里面的<bean>标签

    xml版:

    <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.wang.bean.Person">
    <property name="name" value="张三"></property>
    <property name="age" value="18"></property>
    </bean>
    </beans>

    注解版:

    //在配置类里配置
    @Configuration//告诉spring这是一个配置类
    public class PersonConfig {
        @Bean(value = "person") //给spring容器注册一个bean,类型为返回值类型,id是默认是方法名为id,也可以使用value指定
        public Person person(){
            return new Person("lisi",20);
        }
    }

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

    该注解会自动扫描包路径下面的所有@Controller、@Service、@Repository、@Component 的类

    xml版:

     <!--包扫描,只要注解了@Component,@Controller等会被扫描-->
        <context:component-scan base-package="com.wang" use-default-filters="false" >
            <!--排除某个注解,除了Controller其他类都会被扫描-->
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
            <!--只包含某个注解-->
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>

    注解版:

    @ComponentScan(value = "com.wang"/*excludeFilters = {  //排除
            @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class,Service.class}) //排除Controller和Service
    },*/,includeFilters = { //只包含
           @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Repository.class}) 
    /*,@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})*/ //自定义注解
    },useDefaultFilters = false) //这里要加useDefaultFilters=false让默认的过滤器失效

    其中Filter的type的类型有:

    1. FilterType.ANNOTATION 按照注解

    2. FilterType.ASSIGNABLE_TYPE 按照类型  FilterType.REGEX 按照正则

    3.  FilterType.ASPECTJ 按照ASPECJ表达式规则

    4. FilterType.CUSTOM 使用自定义规则

    其中自定义规则类型过滤器需要实现TypeFilter接口:

    package com.wang.config;
    
    import org.springframework.core.io.Resource;
    import org.springframework.core.type.AnnotationMetadata;
    import org.springframework.core.type.ClassMetadata;
    import org.springframework.core.type.classreading.MetadataReader;
    import org.springframework.core.type.classreading.MetadataReaderFactory;
    import org.springframework.core.type.filter.TypeFilter;
    
    import java.io.IOException;
    //自定义类型过滤器
    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--->"+className);
    
            if (className.contains("Dao")){
                return true;
            }else {
                return false;
            }
    
        }
    }

    3.@Scop 设置组件作用域

    xml版:

     <bean id="person" class="com.wang.bean.Person" scope="prototype">
            <property name="name" value="张三"></property>
            <property name="age" value="18"></property>
        </bean>

    注解版:

    @Bean
    /**
    * prototype 多例,ioc容器创建完成后,要获取的时候才会被调用,多次获取会多次调用
    * singleton 单例(默认),ioc容器启动会调用方法创建对象放到ioc中,以后直接从容器中获取
    * request 同一次请求创建一个实例
    * session 同一个session创建一个实例
    *
    */
    @Scope("prototype")
    public Person person(){
    System.out.println("添加Person....");
    return new Person("张三",23);
    }

     

    4.@Lazy 懒加载bean

    xml版本:

      <bean id="person" class="com.wang.bean.Person" scope="prototype" lazy-init="true">
            <property name="name" value="张三"></property>
            <property name="age" value="18"></property>
        </bean>

    注解版:

     /**
         *
         * 单实例bean,默认在容器启动的时候创建对象
         * 懒加载:容器启动不创建对象,第一次使用(获取)创建Bean,并初始化,第二次使用就使用第一次创建的对象
         *
         */
        @Lazy
    
    
    

    5.@Conditional按照条件注册bean

     @Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。下面给个例子,判断当前项目的运行环境,如果是Windows系统,注册id为win的bean,若是Linux系统,注册id为lin的bean

    1).实现Condition接口
    public class WindowsCondition implements Condition {
        /**
         *
         * @param conditionContext 判断条件能使用的上下文环境
         * @param annotatedTypeMetadata 当前标注了condition的注释信息
         * @return
         */
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            //1.获取ioc的BeanFactory
            ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
            //2.获取类加载器
            ClassLoader classLoader = conditionContext.getClassLoader();
            //3.获取当前环境信息
            Environment environment = conditionContext.getEnvironment();
            //4.获取所有bean定义的注册类
            BeanDefinitionRegistry registry = conditionContext.getRegistry();
    
            String property = environment.getProperty("os.name");
    
            if (property.contains("Windows")){
                return true;
            }
            else {
                return false;
            }
    
        }
    }
    
    
    package com.wang.condition;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.env.Environment;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class LinuxCondition implements Condition {
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            //3.获取当前环境信息
            Environment environment = conditionContext.getEnvironment();
            String property = environment.getProperty("os.name");
    
            if (property.contains("Linux")){
                return true;
            }
            else {
                return false;
            }
        }
    }
    2).在Bean上配置注解
    @Configuration
    public class ConditionConfig {
        /**
         * @Conditional({})按照一定条件进行判断,满足条件容器中注册bean,
         * 若放在类中,整个配置类中的bean满足条件才会被加载到容器中
         *
         * 若是windows系统,注册win,若是linux注册lin
         */
        @Bean("win")
        @Conditional(WindowsCondition.class)
        public Person person(){
            return new Person("win",22);
        }
    
        @Bean("lin")
        @Conditional(LinuxCondition.class)
        public Person person2(){
            return new Person("lin",11);
        }
        @Bean("person")
        public Person person3(){
            return new Person("person",25);
        }
    }
    
    
  • 相关阅读:
    Apollo配置中心环境搭建(Linux)
    SpringBoot整合Swagger2
    DevExpress ASP.NET v18.2新功能详解(四)
    UI控件Telerik UI for WinForms发布R1 2019|附下载
    DevExpress WinForms使用教程:Data Grid
    开发框架DevExtreme全新发布v18.2.6|附下载
    DevExpress ASP.NET v18.2新功能详解(三)
    .NET界面控件DevExpress全新发布v18.2.6|附下载
    DevExpress WinForms使用教程:图表控件
    VCL界面控件DevExpress VCL Controls发布v18.2.4|附下载
  • 原文地址:https://www.cnblogs.com/wangxiayun/p/10083217.html
Copyright © 2020-2023  润新知