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

posted @ 2018-12-07 15:32  薛定谔病态猫  阅读(244)  评论(0编辑  收藏  举报