2、Spring注解开发,第二天

第二天:Spring annotation开发

目录:1、TypeFilter指定过滤规则 2、Scope设置组件作用域 3、懒加载Lazy 4、Conditional按条件注册bean

一、TypeFilter指定过滤规则

最常用的两个
FilterType.Annotation	按照注解
FilterType.ASSIGNABLE_TYPE  按照给定的类型
自定义规则
FilterType.Custom  自定义规则--实现TypeFilter接口[TypeFilter和FilterType有区别的]

1、FilterType.ASSIGNABLE_TYPE

package com.lee.config;

import com.lee.bean.Person;
import com.lee.service.BookService;
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.stereotype.Controller;

//@ComponentScan("com.lee")//自动扫描 value指定要扫描的包
@Configuration//告诉Spring这是一个配置类
//@ComponentScan(value="com.lee",excludeFilters = {
//        @ComponentScan.Filter(type=FilterType.ANNOTATION,value = Controller.class)
//})
@ComponentScan(value = "com.lee",useDefaultFilters=false,includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class),
        @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,value= BookService.class)
})
//FilterType.ANNOTATION 按照注解
//FilterType.ASSIGNABLE_TYPE 按照给定的类型
//FilterType.CUSTOM 按照自定义
public class MainConfig {

    //Bean 给容器注册一个bean,类型为返回值的类型,id默认使用方法名作为id
    //@Bean("名字")可以给bean修改名称
    @Bean
    public Person person(){
        return new Person(2,"lee2","male2");
    }


}

结果

mainConfig
bookController
bookService
person

2、FilterType.Custom

#metadataReader the metadata reader for the target class
#metadataReaderFactory  a factory for obtaining metadata readers for other classes (such as superclasses and interfaces)

MyTypeFilter.class

package com.lee.config;


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 {


    /**
     *
     * @param metadataReader 读取到当前正在扫描类的信息
     * @param metadataReaderFactory  一个工厂,可以获取到任何类的信息
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        System.out.println("======>"+classMetadata.getClassName());
        if(classMetadata.getClassName().contains("ao")){
            System.out.println("---->"+classMetadata.getClassName());
            return true;
        }

        return false;
    }
}

MainConfig.class

package com.lee.config;

import com.lee.bean.Person;
import com.lee.service.BookService;
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.stereotype.Controller;

//@ComponentScan("com.lee")//自动扫描 value指定要扫描的包
@Configuration//告诉Spring这是一个配置类
//@ComponentScan(value="com.lee",excludeFilters = {
//        @ComponentScan.Filter(type=FilterType.ANNOTATION,value = Controller.class)
//})
@ComponentScan(value = "com.lee",useDefaultFilters=false,includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class),
        @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,value= BookService.class),
        @ComponentScan.Filter(type=FilterType.CUSTOM,value = MyTypeFilter.class)
})
//FilterType.ANNOTATION 按照注解
//FilterType.ASSIGNABLE_TYPE 按照给定的类型
//FilterType.CUSTOM 按照自定义
public class MainConfig {

    //Bean 给容器注册一个bean,类型为返回值的类型,id默认使用方法名作为id
    //@Bean("名字")可以给bean修改名称
    @Bean
    public Person person(){
        return new Person(2,"lee2","male2");
    }


}

结果:

mainConfig
bookController
bookDao
bookService
person

二、Scope设置组件作用域

spring默认Bean都是单实例的

1、单例-SINGLETON

MainConfig2.class

package com.lee.config;

import com.lee.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@ComponentScan(value = "com.lee")//包扫描
@Configuration//这是个配置类
public class MainConfig2 {

    @Bean
    public Person person(){
        return new Person(1,"张三","male");
    }
}

MainTest.class

package com.lee;

import com.lee.bean.Person;
import com.lee.config.MainConfig;
import com.lee.config.MainConfig2;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest {


    @Test
    public void test01(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        Person person1 = (Person) context.getBean("person");
        Person person2 = (Person) context.getBean("person");
        System.out.println("person1 == person2 : "+(person1==person2));
    }

}

结果:

person1 == person2 : true

2、原型-PROTOTYPE

MainConfig2.class

package com.lee.config;

import com.lee.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@ComponentScan(value = "com.lee")//包扫描
@Configuration//这是个配置类
public class MainConfig2 {

    @Scope(value = "prototype")
    @Bean
    public Person person(){
        return new Person(1,"张三","male");
    }
}

结果:

person1 == person2 : false

三、懒加载

单实例bean:默认在容器启动的时候创建对象

懒加载:容器启动不创建对象,等第一次调用的时候才创建对象

1、默认

MainConfig2.class

package com.lee.config;

import com.lee.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@ComponentScan(value = "com.lee")//包扫描
@Configuration//这是个配置类
public class MainConfig2 {

    @Scope(value = "prototype")
    @Bean
    public Person person(){
        return new Person(1,"张三","male");
    }
}

2、懒加载 lazy

MainConfig2.class

package com.lee.config;

import com.lee.bean.Person;
import org.springframework.context.annotation.*;

@ComponentScan(value = "com.lee")//包扫描
@Configuration//这是个配置类
public class MainConfig2 {

    @Lazy//懒加载
    @Scope(value = "prototype")
    @Bean
    public Person person(){
        return new Person(1,"张三","male");
    }
}

三、Conditional按条件注册bean

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

WindowsCondition.class

package com.lee.conditions;


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 WindowsCondition implements Condition {


    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if(property.contains("Window")){
            return true;
        }
        return false;
    }
}

LinuxCondition.class

package com.lee.conditions;

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 context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if(property.contains("linux")){
            return true;
        }
        return false;
    }
}

MainConfig2.class

package com.lee.config;

import com.lee.bean.Person;
import com.lee.conditions.LinuxCondition;
import com.lee.conditions.WindowsCondition;
import org.springframework.context.annotation.*;

@ComponentScan(value = "com.lee")//包扫描
@Configuration//这是个配置类
public class MainConfig2 {

//    @Lazy//懒加载
//    @Scope(value = "prototype")
    @Bean
    public Person person(){
        return new Person(1,"张三","male");
    }


    @Conditional({WindowsCondition.class})
    @Bean("bill")
    public Person person01(){
        return new Person(2,"bill Gates","male");
    }

    @Conditional(LinuxCondition.class)
    @Bean("linus")
    public Person person02(){
        return new Person(3,"linus","male");
    }
}

MainTest.class

public class MainTest {

    @Test
    public void test02(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        ConfigurableEnvironment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        System.out.println("===>"+property);
        String[] beanNamesForType = context.getBeanNamesForType(Person.class);
        for(String bean : beanNamesForType){
            System.out.println(bean);
        }
    }
}

结果:

===>Windows 10
person
bill

在Run/Debug Configurations中加入环境变量

-Dos.name=linux

结果:

===>Linux
person
linus

@Conditional不仅可以标注在方法method上,也可以标注在类class上,这个类中所有bean注册才能被生效

上一篇:1、Spring注解开发,第一天


下一篇:LeetCode 1249. Minimum Remove to Make Valid Parentheses