Spring注解驱动——IOC

2021-03-09 14:30

阅读:516

标签:local   autowire   上下文   close   int   throw   proc   linus   sig   

体系结构概述

技术图片

 

@Bean

之前时候,在xml配置文件使用:

bean id="person" class="com.atguigu.bean.Person"  scope="prototype" >
        property name="age" value="${}">property>
        property name="name" value="zhangsan">property>
    bean>

实体类:

public class Person {
    private String name;private Integer age;
   public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    
    public Person(String name, Integer age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Person() {
        super();
        // TODO Auto-generated constructor stub
    }

    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]";
    }

}

测试:

public class MainTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Person bean = (Person) applicationContext.getBean("person");
        System.out.println(bean);
      
    }

}

注解方式

写一个配置类:需要@Configuration注解

//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类
public class MainConfig {
    
    //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id,也可以指定id名为什么
    @Bean("person")
    public Person person01(){
        return new Person("lisi", 20);
    }

}

测试:

public class MainTest {
    
    @SuppressWarnings("resource")
    public static void main(String[] args) {
       
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        Person bean = applicationContext.getBean(Person.class);
        System.out.println(bean);
        
        String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
        for (String name : namesForType) {
            System.out.println(name);
        }
    
    }

}

 

@ComponentScan

之前在xml配置文件里配置:

context:component-scan base-package="com.atguigu" use-default-filters="false">context:component-scan>

现在配置在类上:

//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类
@ComponentScan(value="com.atguigu")  // value:指定要扫描的包
public class MainConfig {
    
    //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
    @Bean("person")
    public Person person01(){
        return new Person("lisi", 20);
    }

}

 @ComponentScan 的一般配置项:

@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:使用自定义规则

可以修改默认的过滤规则,写一个类,实现FilterType

public class MyTypeFilter implements TypeFilter {
    /**
     * metadataReader:读取到的当前正在扫描的类的信息
     * metadataReaderFactory:可以获取到其他任何类信息的
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {
        // TODO Auto-generated method stub
        //获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描的类的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类资源(类的路径)
        Resource resource = metadataReader.getResource();
        
        String className = classMetadata.getClassName();
        System.out.println("--->"+className);
        if(className.contains("er")){
            return true;
        }
        return false;
    }
}

@ComponentScan 可以在类上面写多个,也可以通过一个 @ComponentScans 注解来把多个 @ComponentScan 注解配置放在里面,两个写法都是一样的可以生效

@ComponentScans(
        value = {
                @ComponentScan(value="com.atguigu",includeFilters = {
                        @Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
                },useDefaultFilters = false)    
        }
        )

 

Spring 的默认注册组件都是单例的,可以用@Scope 注解修改bean 的作用域

虽然Spring 是单例的,但它用的是饿汉式单例,在Spring 启动时候,就已经把对象注册到了Spring 容器里,可以用@Lazy 注解让它变成懒加载,不过不推荐修改

   //默认是单实例的
    /**
     * ConfigurableBeanFactory#SCOPE_PROTOTYPE    
     * @see ConfigurableBeanFactory#SCOPE_SINGLETON  
     * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST  request
     * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION     sesssion
     * @return     * @Scope:调整作用域
     * prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。
     *                     每次获取的时候才会调用方法创建对象;
     * singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。
     *             以后每次获取就是直接从容器(map.get())中拿,
     * request:同一次请求创建一个实例
     * session:同一个session创建一个实例
     * 
     * 懒加载:
     *         单实例bean:默认在容器启动的时候创建对象;
     *         懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化;
     */
//    @Scope("prototype")
    @Lazy
    @Bean("person")
    public Person person(){
        System.out.println("给容器中添加Person....");
        return new Person("张三", 25);
    }

@Conditional 按照条件给Spring 注册bean,

   /**
     * @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean
     * 
     * 如果系统是windows,给容器中注册("bill")
     * 如果是linux系统,给容器中注册("linus")
     */
    
    @Bean("bill")
    public Person person01(){
        return new Person("Bill Gates",62);
    }
    
    @Conditional(LinuxCondition.class)
    @Bean("linus")
    public Person person02(){
        return new Person("linus", 48);
    }

获取是否是Linux系统的类:

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

//判断是否linux系统
public class LinuxCondition implements Condition {
    /**
     * ConditionContext:判断条件能使用的上下文(环境)
     * AnnotatedTypeMetadata:注释信息
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // TODO是否linux系统
        //1、能获取到ioc使用的beanfactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //2、获取类加载器
        ClassLoader classLoader = context.getClassLoader();
        //3、获取当前环境信息
        Environment environment = context.getEnvironment();
        //4、获取到bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();
        
        String property = environment.getProperty("os.name");
        
        //可以判断容器中的bean注册情况,也可以给容器中注册bean
        boolean definition = registry.containsBeanDefinition("person");
        if(property.contains("linux")){
            return true;
        }
        return false;
    }
}

获取是否是Windows系统的类:

//判断是否windows系统
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("Windows")){
            return true;
        }
        return false;
    }
}

测试:

   @Test
    public void test03(){
        String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        //动态获取环境变量的值;Windows 10
        String property = environment.getProperty("os.name");
        System.out.println(property);
        for (String name : namesForType) {
            System.out.println(name);
        }
        Map persons = applicationContext.getBeansOfType(Person.class);
        System.out.println(persons);
    }

@Conditional 注解可以放在方法是,也可以放在类上

技术图片

 

 @Import

1、给容器导入一个组件

要导入的组件

public class Color {
    private Car car;

    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Color [car=" + car + "]";
    }
}

Car 类:

public class Car {
}

导入:

@Import({Color.class})
//@Import导入组件,id默认是组件的全类名
public class MainConfig2 {

2、也可以导入多个:

添加两个颜色的类:

public class Blue {
}
public class Yellow {

}

要写一个类,实现ImportSelector 接口,然后通过这个类,就导入了多个组件

//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
    //返回值,就是到导入到容器中的组件全类名
    //AnnotationMetadata:当前标注@Import注解的类的所有注解信息
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // TODO Auto-generated method stub
        //importingClassMetadata
        //方法不要返回null值
        return new String[]{"com.atguigu.bean.Blue","com.atguigu.bean.Yellow"};
    }
}

导入多个:虽然 MyImportSelector 看着 和导入一个组件是一样的,导入了一个类而已,但是这个类里添加了多个组件

@Import({Color.class,Red.class,MyImportSelector.class})
//@Import导入组件,id默认是组件的全类名
public class MainConfig2 {

3、通过ImportBeanDefinitionRegistrar 接口手动导入组件

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * AnnotationMetadata:当前类的注解信息
     * BeanDefinitionRegistry:BeanDefinition注册类;
     *         把所有需要添加到容器中的bean;调用
     *         BeanDefinitionRegistry.registerBeanDefinition手工注册进来
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        
        boolean definition = registry.containsBeanDefinition("com.atguigu.bean.Red");
        boolean definition2 = registry.containsBeanDefinition("com.atguigu.bean.Blue");
        if(definition && definition2){
            //指定Bean定义信息;(Bean的类型,Bean。。。)
            RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
            //注册一个Bean,指定bean名
            registry.registerBeanDefinition("rainBow", beanDefinition);
        }
    }

}

新加的彩虹类:

public class RainBow {

}

4、使用FactoryBean 注册组件

创建Bean 的工厂:

//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean {

    //返回一个Color对象,这个对象会添加到容器中
    @Override
    public Color getObject() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("ColorFactoryBean...getObject...");
        return new Color();
    }

    @Override
    public Class> getObjectType() {
        // TODO Auto-generated method stub
        return Color.class;
    }

    //是单例?
    //true:这个bean是单实例,在容器中保存一份
    //false:多实例,每次获取都会创建一个新的bean;
    @Override
    public boolean isSingleton() {
        // TODO Auto-generated method stub
        return false;
    }
}

用的时候:

   @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }

测试:

   @Test
    public void testImport(){
        printBeans(applicationContext);
        Blue bean = applicationContext.getBean(Blue.class);
        System.out.println(bean);
        
        //工厂Bean获取的是调用getObject创建的对象
        Object bean2 = applicationContext.getBean("colorFactoryBean");
        Object bean3 = applicationContext.getBean("colorFactoryBean");
        System.out.println("bean的类型:"+bean2.getClass());
        System.out.println(bean2 == bean3);
        // 虽然导入的是colorFactoryBean,但打印的还是color,如果非要获取的是工厂bean名字,就在前面加一个& 就好了
        Object bean4 = applicationContext.getBean("&colorFactoryBean");
        System.out.println(bean4.getClass());
    }

总结:

   /**
     * 给容器中注册组件;
     * 1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
     * 2)、@Bean[导入的第三方包里面的组件]
     * 3)、@Import[快速给容器中导入一个组件]
     *         1)、@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
     *         2)、ImportSelector:返回需要导入的组件的全类名数组; (比较重要,在SpringBoot 里用的非常多)
     *         3)、ImportBeanDefinitionRegistrar:手动注册bean到容器中
     * 4)、使用Spring提供的 FactoryBean(工厂Bean);
     *         1)、默认获取到的是工厂bean调用getObject创建的对象
     *         2)、要获取工厂Bean本身,我们需要给id前面加一个&
     *             &colorFactoryBean
     */
    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }

 

生命周期

要注册Bean 的类:

1、第一种方式需要的Bean

@Component
public class Car {
    
    public Car(){
        System.out.println("car constructor...");
    }
    
    public void init(){
        System.out.println("car ... init...");
    }
    
    public void detory(){
        System.out.println("car ... detory...");
    }

}

2、第二种方式的Bean

@Component
public class Cat implements InitializingBean,DisposableBean {
    
    public Cat(){
        System.out.println("cat constructor...");
    }

    @Override
    public void destroy() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("cat...destroy...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("cat...afterPropertiesSet...");
    }

}

3、第三种方式的

@Component
public class Dog implements ApplicationContextAware {  
    
    //@Autowired
    private ApplicationContext applicationContext;  // 实现上面类的接口,这样导入后,以后用的时候就可以拿到IOC容器
    
    public Dog(){
        System.out.println("dog constructor...");
    }
    
    //对象创建并赋值之后调用
    @PostConstruct
    public void init(){
        System.out.println("Dog....@PostConstruct...");
    }
    
    //容器移除对象之前
    @PreDestroy
    public void detory(){
        System.out.println("Dog....@PreDestroy...");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // TODO Auto-generated method stub
        this.applicationContext = applicationContext;
    }
}

4、使用Bean 的后置处理器

/**
 * 后置处理器:初始化前后进行处理工作
 * 将后置处理器加入到容器中*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
        return bean;
    }
}

注册Bean

/**
 * bean的生命周期:
 *         bean创建---初始化----销毁的过程
 * 容器管理bean的生命周期;
 * 我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
 * 
 * 构造(对象创建)
 *         单实例:在容器启动的时候创建对象
 *         多实例:在每次获取的时候创建对象 * 
 * BeanPostProcessor.postProcessBeforeInitialization
 * 初始化:
 *         对象创建完成,并赋值好,调用初始化方法。。。
 * BeanPostProcessor.postProcessAfterInitialization
 * 销毁:
 *         单实例:容器关闭的时候
 *         多实例:容器不会管理这个bean;容器不会调用销毁方法;
 * 
 * 
 * 遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
 * 一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
 * 
 * BeanPostProcessor原理
 * populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
 * initializeBean
 * {
 * applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
 * invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
 * applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 *}
 * 
 * 
 * 创建Bean的4种方式
 * 1)、指定初始化和销毁方法;
 *         通过@Bean指定init-method和destroy-method;分别指定初始化 或 销毁时候 调用的方法
 * 2)、通过让Bean实现InitializingBean(定义初始化逻辑),
 *                 DisposableBean(定义销毁逻辑);
*      实现这两个接口,然后重写里面的两个方法 * 3)、可以使用JSR250; * @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法,定义在方法上 * @PreDestroy:在容器销毁bean之前通知我们进行清理工作,也在方法上定义 * 4)、BeanPostProcessor【interface】:bean的后置处理器; * 在bean初始化前后进行一些处理工作; * postProcessBeforeInitialization:在初始化之前工作 * postProcessAfterInitialization:在初始化之后工作 * * Spring底层对 BeanPostProcessor 的使用; * bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async, 。。。BeanPostProcessor; *
*/ @ComponentScan("com.atguigu.bean") @Configuration public class MainConfigOfLifeCycle { //@Scope("prototype") @Bean(initMethod="init",destroyMethod="detory") public Car car(){ return new Car(); } }

测试:

public class IOCTest_LifeCycle {
    
    @Test
    public void test01(){
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");
        
        //applicationContext.getBean("car");
        //关闭容器
        applicationContext.close();
    }

}

 

属性赋值

@Value 

public class Person {
    
    //使用@Value赋值;
    //1、基本数值
    //2、可以写SpEL; #{}
    //3、可以写${};取出配置文件【properties】中的值(在运行环境变量里面的值)
    
    @Value("张三")
    private String name;
    @Value("#{20-2}")  // 18
    private Integer age;
    
    @Value("${person.nickName}")  // 导入的是配置文件的值
    private String nickName;
   
person.nickName=\u5C0F\u674E\u56DB    // 小张三

之前在xml 文件要配置的:

context:property-placeholder location="classpath:person.properties"/>

现在可以在类上使用@PropertySource,如果要加入多个配置文件,可以点进去看源码,比较简单,可以放数组类型

//使用@PropertySource读取外部配置文件中的k/v保存到运行的环境变量中;加载完外部的配置文件以后使用${}取出配置文件的值
@PropertySource(value={"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {
    
    @Bean
    public Person person(){
        return new Person();
    }
}

 

自动装配

第一种:我们开发中对dao、service、controller 都要加上三个注解,然后互相之间调用时候使用@Autowired 把我们自定义的组件给自动装配进来,它是按照类型来注入的,默认的Bean是类的首字母小写,

  如果找到了多个Bean,再按照属性名查找,如果要必须指定注入哪个,就用@Qualifier("指定的bean的名字"),@Autowired 可以指定是否一定要找spring 里的bean,加上required 属性就行,

  还有一个注解@Primary首选去找到哪个bean,而@Qualifier 是必须要用哪个bean

  @Autowired 可以在 构造器,参数,方法,属性,都可以使用

  第二种:还可以使用@Resource 也可以完成自动装配,不同的是@Resource 是java里的注解,@Autowired 是spring里的注解,@Resource 默认是按照属性名装配的,

    @Resource 不能和@Autowired 一样搭配着其他两个注解一块使用

    @Inject 也可以自动装配,也是java的注解,但是需要导入javax.inject的包,和Autowired的功能一样。没有required=false的功能;

/**
 * 自动装配;
 *         Spring利用依赖注入(DI),完成对IOC容器中中各个组件的依赖关系赋值;
 * 
 * 1)、@Autowired:自动注入:
 *         1)、默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);找到就赋值
 *         2)、如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找
 *                             applicationContext.getBean("bookDao")
 *         3)、@Qualifier("bookDao"):使用@Qualifier指定需要装配的组件的id,而不是使用属性名
 *         4)、自动装配默认一定要将属性赋值好,没有就会报错;
 *             可以使用@Autowired(required=false);
 *         5)、@Primary:让Spring进行自动装配的时候,默认使用首选的bean;
 *                 也可以继续使用@Qualifier指定需要装配的bean的名字
 *         BookService{
 *             @Autowired
 *             BookDao  bookDao;
 *         }
 * 
 * 2)、Spring还支持使用@Resource(JSR250)和@Inject(JSR330)[java规范的注解]
 *         @Resource:
 *             可以和@Autowired一样实现自动装配功能;默认是按照组件名称进行装配的;
 *             没有能支持@Primary功能没有支持@Autowired(reqiured=false);
 *         @Inject:
 *             需要导入javax.inject的包,和Autowired的功能一样。没有required=false的功能;
 *  @Autowired:Spring定义的; @Resource、@Inject都是java规范
 *     
 * AutowiredAnnotationBeanPostProcessor:解析完成自动装配功能;        
 * 
 * 3)、 @Autowired:构造器,参数,方法,属性;都是从容器中获取参数组件的值
 *         1)、[标注在方法位置]:@Bean+方法参数;参数从容器中获取;默认不写@Autowired效果是一样的;都能自动装配
 *         2)、[标在构造器上]:如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取
 *         3)、放在参数位置:
 * 
 * 4)、自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx);
 *         自定义组件实现xxxAware;在创建对象的时候,会调用接口规定的方法注入相关组件;Aware;
 *         把Spring底层一些组件注入到自定义的Bean中;
 *         xxxAware:功能使用xxxProcessor;
 *             ApplicationContextAware==》ApplicationContextAwareProcessor;
 *     */
@Configuration
@ComponentScan({"com.atguigu.service","com.atguigu.dao",
    "com.atguigu.controller","com.atguigu.bean"})
public class MainConifgOfAutowired {
    
    @Primary
    @Bean("bookDao2")
    public BookDao bookDao(){
        BookDao bookDao = new BookDao();
        bookDao.setLable("2");
        return bookDao;
    }
    /**
     * @Bean标注的方法创建对象的时候,方法参数的值从容器中获取
     * @param car
     * @return
     */
    @Bean
    public Color color(Car car){
        Color color = new Color();
        color.setCar(car);
        return color;
    }    
}

@Autowired 在 构造器,参数,方法,属性 上面使用

//默认加在ioc容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作
@Component
public class Boss {        
    private Car car;
    
    //构造器要用的组件,都是从容器中获取
    public Boss(Car car){
        this.car = car;
        System.out.println("Boss...有参构造器");
    }        
    public Car getCar() {
        return car;
    }
    //@Autowired 
    //标注在方法,Spring容器创建当前对象,就会调用方法,完成赋值;
    //方法使用的参数,自定义类型的值从ioc容器中获取
    public void setCar(Car car) {
        this.car = car;
    }
    @Override
    public String toString() {
        return "Boss [car=" + car + "]";
    }    
}

Aware 注入spring底层组件测试

@Component
public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware {
    
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("传入的ioc:"+applicationContext);
        this.applicationContext = applicationContext;
    }
    @Override
    public void setBeanName(String name) {
        // TODO Auto-generated method stub
        System.out.println("当前bean的名字:"+name);
    }
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        // TODO Auto-generated method stub
        String resolveStringValue = resolver.resolveStringValue("你好 ${os.name} 我是 #{20*18}");
        System.out.println("解析的字符串:"+resolveStringValue);
    }
}

 

@Profile 可以切换项目的当前环境,如果不用@Profile 指定,默认不管哪个环境都可以注册的,@Profile 也可以写在类上

/**
 * Profile:
 *         Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
 * 
 * 开发环境、测试环境、生产环境;
 * 数据源:(/A)(/B)(/C);
 * 
 * 
 * @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
 * 
 * 1)、加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
 * 2)、写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
 * 3)、没有标注环境标识的bean在,任何环境下都是加载的;
 */

@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
    
    @Value("${db.user}")
    private String user;    
private StringValueResolver valueResolver; // 值解析器 private String driverClass; @Bean public Yellow yellow(){ return new Yellow(); } @Profile("test") @Bean("testDataSource") public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); dataSource.setDriverClass(driverClass); return dataSource; } @Profile("dev") @Bean("devDataSource") public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud"); dataSource.setDriverClass(driverClass); return dataSource; } @Profile("prod") @Bean("prodDataSource") public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515"); dataSource.setDriverClass(driverClass); return dataSource; } @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { // TODO Auto-generated method stub this.valueResolver = resolver; driverClass = valueResolver.resolveStringValue("${db.driverClass}"); } }

配置文件   dbconfig.properties

db.user=root
db.password=123456
db.driverClass=com.mysql.jdbc.Driver

测试:

public class IOCTest_Profile {
    //1、使用命令行动态参数: 在虚拟机参数位置加载 -Dspring.profiles.active=test
    //2、代码的方式激活某种环境;
    @Test
    public void test01(){
        AnnotationConfigApplicationContext applicationContext = 
                new AnnotationConfigApplicationContext();
        //1、创建一个applicationContext
        //2、设置需要激活的环境,可以设置多个,,隔开
        applicationContext.getEnvironment().setActiveProfiles("dev");
        //3、注册主配置类
        applicationContext.register(MainConfigOfProfile.class);
        //4、启动刷新容器
        applicationContext.refresh();
        
        
        String[] namesForType = applicationContext.getBeanNamesForType(DataSource.class);
        for (String string : namesForType) {
            System.out.println(string);
        }        
        Yellow bean = applicationContext.getBean(Yellow.class);
        System.out.println(bean);
        applicationContext.close();
    }
}

 

Spring注解驱动——IOC

标签:local   autowire   上下文   close   int   throw   proc   linus   sig   

原文地址:https://www.cnblogs.com/abiu/p/14152044.html


评论


亲,登录后才可以留言!