• 浅尝Spring注解开发_自定义注册组件、属性赋值、自动装配


    Spring注解开发_自定义注册组件、属性赋值、自动装配、环境标识

    浅尝Spring注解开发,基于Spring 4.3.12
    包含自定义扫描组件、自定义导入组件、手动注册组件、自动注入方法和参数、使用Spring容器底层组件等

    浅尝Spring注解开发_自定义注册组件、属性赋值、自动装配
    浅尝Spring注解开发_Bean生命周期及执行过程
    浅尝Spring注解开发_AOP原理及完整过程分析(源码)
    浅尝Spring注解开发_声明式事务及原理
    浅尝Spring注解开发_简单理解BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor、ApplicationListener
    Spring注解开发_Spring容器创建概述
    浅尝Spring注解开发_Servlet3.0与SpringMVC

    配置

    @Configuration配置类

    告诉Spring这是一个配置类,代替以前的xml文件,配置类=配置文件

    @Configuration
    public class MainConfig {
    	
    	//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
    	@Bean("person")
    	public Person person01(){
    		return new Person("lisi", 20);
    	}
    
    }

    注册组件

    给容器中注册组件有以下方法:

    1. 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]

    2. @Bean[导入的第三方包里面的组件]

    3. @Import[快速给容器中导入一个组件]

      1. @Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
      2. ImportSelector:返回需要导入的组件的全类名数组;
      3. ImportBeanDefinitionRegistrar:手动注册bean到容器中
    4. 使用Spring提供的 FactoryBean(工厂Bean);

      1. 默认获取到的是工厂bean调用getObject创建的对象

      2. 要获取工厂Bean本身,我们需要给id前面加一个&

        如:&colorFactoryBean

    @Bean注册

    给容器中注册一个Bean,类型为返回值的类型,id默认是用方法名作为id,也可以指定id

    	@Bean("person")//指定Bean id
    	public Person person01(){
    		return new Person("lisi", 20);
    	}

    IoC容器

    创建一个IoC容器AnnotationConfigApplicationContext,传入配置类,获取Bean

    //创建IoC容器
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
    
    //获取Bean对象
    Person bean = applicationContext.getBean(Person.class);
    
    //获取所以Person类型Bean的名字
    String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
    for (String name : namesForType) {
    	System.out.println(name);
    }

    ⭐@ComponentScan扫描组件

    @Component(包括@Controller@Service@Repository和@Bean目的一样)和@ComponentScan的区别

    • @Component:将普通JavaBean实例化到spring容器中,Spring容器统一管理,用起来不用自己new了,相当于配置文件中的
    • @ComponentScan:一般用在核心配置类,由你来定义哪些包需要被扫描。
    • @Component标在类上,@Bean标在方法上,两者使用在普通类或方法上时,都不起作用,只有放在配置类中才能注册组件(@Bean可以在写在配置类中,@Component由于本身标在类上,所以不能写在类中),而@ComponentScan就是给了@Component一种注册进容器的办法,只要扫描到@Component标注的类就直接注册进容器
    • 自动扫描组件,可有多个@ComponentScan,或一个@ComponentScans

    • value:指定要扫描的包

      所有指定的包下的类都要进入扫描,是否能够通过,需要看下面使用了什么规则,有排除、包含、指定类型、正则、和自定义规则,自定义规则通过反射获取包中所有类,然后判断是否能够进入ioc容器中。

    • excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件

    • includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件

      • ​ FilterType.ANNOTATION:按照注解
      • ​ FilterType.ASSIGNABLE_TYPE:按照给定的类型
      • ​ FilterType.ASPECTJ:使用ASPECTJ表达式
      • ​ FilterType.REGEX:使用正则指定
    • ​ FilterType.CUSTOM:使用自定义规则,需要TypeFilter实现类

    • useDefaultFilters:不使用默认的 Filter进行扫描。在includeFilters中使用,取消默认扫描,指定扫描对象,可以在SpringMVC中使用

    @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)

    FilterType.CUSTOM:使用自定义规则,需要实现TypeFilter接口

    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);
    		//根据自定义规则,只让类名中包含er的类进入ioc容器。
    		if(className.contains("er")){
    			return true;
    		}
    		return false;
    	}
    
    }

    @Scope作用域

    调整作用域,单实例,多实例

    • prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。每次获取的时候才会调用方法创建对象;
    • singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。以后每次获取就是直接从容器(map.get())中拿
    • request:同一次请求创建一个实例。web环境中
    • session:同一个session创建一个实例。web环境中
    	@Scope("singleton")
    	@Lazy
    	@Bean("person")
    	public Person person(){
    		System.out.println("给容器中添加Person....");
    		return new Person("张三", 25);
    	}

    @Lazy懒加载

    • 在单实例bean应用:默认在容器启动的时候创建对象,配置懒加载后,容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化,仍是单实例。

    ⭐@Conditional条件注册Bean

    指定条件向容器中注入Bean

    @Conditional({Condition}) : 按照一定的条件进行判断,满足条件才将Bean注册进容器,可以标在@Bean方法和@Configuration类上

    • 添加了@Conditional({Condition}) 的Bean方法或配置Bean的类,只有在满足Condition中的条件才能执行(装配Bean)
    • Condition:需要实现Condition接口的条件类,可以判断容器中的bean注册情况,也可以给容器中注册bean

    Condition条件实现类

    创建两个判断条件,判断系统是Windows还是Linux,自定义注册不同的Bean,注解可以标在方法上,也可以标在类上

    • 实现Condition接口
    //判断是否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();
    		//5、获取系统名
    		String property = environment.getProperty("os.name");
    		
    		//这里判断容器中的bean注册情况,也可以使用BeanDefinitionRegistry.registerBeanDefinition()给容器中注册bean
    		boolean definition = registry.containsBeanDefinition("person");
    		
    		//判断系统名是否包含linux
    		if(property.contains("linux")){
    			return true;
    		}
    		return false;
    	}
    }
    //判断是否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;
    	}
    
    }

    标在方法上

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

    标在类上

    //类中组件统一设置。满足当前条件,这个类中配置的所有bean注册才能生效;
    @Conditional({WindowsCondition.class})
    @Configuration
    public class MainConfig2 {
    	//...
    }

    测试方法

    • 使用,可配置VM参数:-Dos.name=linux 测试

      public class IOCTest {
          
      	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
      	
      	@Test
      	public void test03(){
      		//获取所有Person类型的Bean名字
      		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);
      		}
      		
      		//获取所有Person类型Bean的对象,名字是否是lunus或bill
      		Map persons = applicationContext.getBeansOfType(Person.class);
      		System.out.println(persons);
      		
      	}
      }

    ⭐@Import注册

    @Import的三种方法都是写在@Import注解中,都是向容器中导入组件

    • @Import(要导入到容器中的组件):容器中就会自动注册这个组件,id默认是全类名
    • ImportSelector:返回需要导入的组件的全类名数组
    • ImportBeanDefinitionRegistrar:手动注册bean到容器中

    @Import

    • @Import(要导入到容器中的组件):容器中就会自动注册这个组件,id默认是全类名com.xxx.bean.Color

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

      public class IOCTest {
          
      	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
      	
      	//输出:除了Spring自己的Bean还有Import的Color、Red
      	@Test
      	public void testImport(){
      		printBeans(applicationContext);
      	}
      	
      	//输出容器中所有的Bean名
      	private void printBeans(AnnotationConfigApplicationContext applicationContext){
      		String[] definitionNames = applicationContext.getBeanDefinitionNames();
      		for (String name : definitionNames) {
      			System.out.println(name);
      		}
      	}
      }

    ⭐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"};
      	}
      
      }
    • 配置

      @Configuration
      //@Import导入组件,MyImportSelector是自定义选择的Bean
      @Import({Color.class,Red.class,MyImportSelector.class})
      public class MainConfig2 {
          //...
      }
    • 测试

      public class IOCTest {
          
      	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
      	
      	//输出:除了Spring自己的Bean还有MyImportSelector选中的Bean
      	@Test
      	public void testImport(){
      		printBeans(applicationContext);
      		Blue bean = applicationContext.getBean(Blue.class);
      		System.out.println(bean);
      	}
      	
      	//输出容器中所有的Bean名
      	private void printBeans(AnnotationConfigApplicationContext applicationContext){
      		String[] definitionNames = applicationContext.getBeanDefinitionNames();
      		for (String name : definitionNames) {
      			System.out.println(name);
      		}
      	}
      }

    ⭐ImportBeanDefinitionRegistrar

    自定义注入组件,在Spring注解源码中使用

    • 实现接口,指定规则,手动注入新的bean

      public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
      
      	/**
      	 * AnnotationMetadata:当前类的注解信息
      	 * BeanDefinitionRegistry内有BeanDefinition注册类,所有Bean都在这里注册;
      	 * 		把所有需要添加到容器中的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定义信息BeanDefinition类型;(Bean的类型,Bean作用域等...)
      			RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
      			//注册一个新Bean,指定bean名
      			registry.registerBeanDefinition("rainBow", beanDefinition);
      		}
      	}
      
      }
    • 配置

      @Configuration
      //MyImportBeanDefinitionRegistrar是手动注册到Bean容器中,可以指定规则
      @Import({Color.class,Red.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
      //@Import导入组件,id默认是组件的全类名
      public class MainConfig2 {
      	//...
      }
    • 测试

      public class IOCTest {
          
      	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
      	
      	//输出:除了Spring自己的Bean还有手动定制规则新导入的rainBow
      	@Test
      	public void testImport(){
      		printBeans(applicationContext);
      		Blue bean = applicationContext.getBean(Blue.class);
      		System.out.println(bean);
      	}
      	
      	//输出容器中所有的Bean名
      	private void printBeans(AnnotationConfigApplicationContext applicationContext){
      		String[] definitionNames = applicationContext.getBeanDefinitionNames();
      		for (String name : definitionNames) {
      			System.out.println(name);
      		}
      	}
      }

    ⭐FactoryBean注册

    多用于第三方组件

    接口,给容器中注入组件,使用Spring提供的 FactoryBean(工厂Bean)创建的Bean

    1. 默认获取到的是工厂bean调用getObject创建的对象,而不是工厂对象本身

    2. 要获取工厂Bean本身,我们需要给id前面加一个"&"如:context.getBean("&xxx")

    • 实现接口,创建工厂

      //创建一个Spring定义的FactoryBean
      public class ColorFactoryBean implements FactoryBean<Color> {
      
      	//返回一个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;
      	}
      
      }
    • 配置

      @Configuration
      public class MainConfig2 {
      	
      	/**
      	 * 给容器中注册组件;
      	 * 4)、使用Spring提供的 FactoryBean(工厂Bean);
      	 * 		1)、默认获取到的是工厂bean调用getObject创建的对象
      	 * 		2)、要获取工厂Bean本身,我们需要给id前面加一个&
      	 * 			&colorFactoryBean
      	 */
      	@Bean
      	public ColorFactoryBean colorFactoryBean(){
      		return new ColorFactoryBean();
      	}
      	
      }
    • 测试

      public class IOCTest {
          
      	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
      	
      	//直接使用输出的不是工厂本身,而是工厂内getObject创建的Bean
      	@Test
      	public void testImport(){
              
      		//工厂Bean获取的是调用getObject创建的Color对象
      		Object bean2 = applicationContext.getBean("colorFactoryBean");
      		Object bean3 = applicationContext.getBean("colorFactoryBean");
      		//输出:com.xxx.bean.Color
      		System.out.println("bean的类型:"+bean2.getClass());
      		System.out.println(bean2 == bean3);
      		
      		//输出:com.xxx.bean.ColorFactoryBean
      		Object bean4 = applicationContext.getBean("&colorFactoryBean");
      		System.out.println(bean4.getClass());
      	}
      	
      	//输出容器中所有的Bean名
      	private void printBeans(AnnotationConfigApplicationContext applicationContext){
      		String[] definitionNames = applicationContext.getBeanDefinitionNames();
      		for (String name : definitionNames) {
      			System.out.println(name);
      		}
      	}
      }

    属性赋值

    @Value赋值

    基本数值

    public class Person {
    	
    	//使用@Value赋值;
    	//1、基本数值
    	@Value("张三")
    	private String name;
    }

    SpEL表达式 #{}

    public class Person {
    	
    	//使用@Value赋值;
    	//1、基本数值
    	//2、可以写SpEL; #{}
    
    	
    	@Value("张三")
    	private String name;
    	
    	//计算后值为18
    	@Value("#{20-2}")
    	private Integer age;
    }

    @PropertySource配置文件取值

    读取properties配置文件的值,例如读取数据库连接信息

    • 读取文件
    • 取值

    读取配置文件

    使用@PropertySource读取外部配置文件

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

    配置文件person.properties

    person.nickName=法外狂徒

    配置文件取值${}

    取出配置文件properties中的值

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

    运行时环境变量取值

    运行时properties配置文件加载进环境变量,可以直接取出

    public class IOCTest_PropertyValue {
    	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
    	@Test
    	public void test01(){
    		//直接从applicationContext容器中获取运行时环境变量ConfigurableEnvironment
    		ConfigurableEnvironment environment = applicationContext.getEnvironment();
    		//取值
    		String property = environment.getProperty("person.nickName");
    		System.out.println(property);
    		applicationContext.close();
    	}
    }

    自动装配

    AutowiredAnnotationBeanPostProcessor:解析完成自动装配功能

    几种自动装配:

    1. @Autowired:自动注入
    2. Spring还支持使用@Resource(JSR250)和@Inject(JSR330)[java规范的注解]
    3. @Autowired:构造器,参数,方法,属性,都是从容器中获取参数组件的值
    4. 自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx)

    @Autowired

    自动注入:

    1. 默认优先按照类型去容器中找对应的组件,同applicationContext.getBean(BookDao.class),找到就赋值
    2. 如果找到多个相同类型的组件,再将属性的名称(@Bean的value或者方法名)作为组件的id去容器中查找,同applicationContext.getBean("bookDao")
    3. 如果都相同就会报错

    @Qualifier

    指定装配:

    • @Qualifier("bookDao"):使用@Qualifier指定需要装配的组件的id,而不是使用属性名自动装配,默认一定要将属性赋值好,没有就会报错;
    • 如果没有就不装配,可以使用@Autowired(required=false)表示

    @Primary

    默认装配:

    • @Primary:让Spring进行自动装配的时候,默认使用首选的bean;
    • 也可以继续使用@Qualifier指定需要装配的bean的名字

    下面是两个Bean的情况

    @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;
    	}
    }
    @Service
    public class BookService {
    	
    	@Qualifier("bookDao")//指定,大于首选
    	@Autowired(required=false)//可以不存在
    	private BookDao bookDao;
    }

    @Resource

    • 可以和@Autowired一样实现自动装配功能,默认是按照组件名称进行装配的

    • 没有能支持@Primary和@Autowired(reqiured=false)的功能

    • @Autowired跟spring强耦合,如果换成了JFinal等其他框架,功能就会失效。而@Resource是JSR-250提供的,它是Java标准,绝大部分框架都支持

    	@Resource(name="bookDao2")
    	private BookDao bookDao;

    @Inject

    • 需要导入javax.inject的包,和@Autowired的功能一样。没有@Autowired(reqiured=false)的功能

    • @Autowired:Spring定义的, @Resource、@Inject都是java规范,@Autowried不能脱离Spring

    	@Inject
    	private BookDao bookDao;

    ⭐@Autowired注入方法,参数

    @Autowired:构造器,参数,方法,属性都是从容器中获取参数组件的值

    使用[@Bean+方法参数]的方式在SpringBoot中使用很多,在使用各种配置时,只配置方法,方法中的参数直接从容器中获取

    1. [标注在方法位置]:@Bean+方法参数,参数从容器中获取,默认不写@Autowired效果是一样的,都能自动装配
    2. [标在构造器上]:如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取
    3. 放在参数位置

    方法上

    • @Autowired直接标在方法上

      	@Autowired 
      	//标注在方法,Spring容器创建当前对象,就会调用方法,完成赋值;
      	//方法使用的参数,自定义类型的值从ioc容器中获取
      	public void setCar(Car car) {
      		this.car = car;
      	}
    • 如果是@Bean标注的方法,参数位置不标@Autowired,参数也可以自动装配,都是从容器中获取

      	/**
      	 * @Bean标注的方法创建对象的时候,方法参数的值从容器中获取
      	 * @param car car也是从容器中获取的值,前提是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;
      	
      	//构造器要用的组件,都是从容器中获取
      	//@Autowired
      	public Boss(Car car){
      		this.car = car;
      		System.out.println("Boss...有参构造器");
      	}
      }

    参数上

    • 标在参数前

      	public void setCar(@Autowired  Car car) {
      		this.car = car;
      	}

    ⭐Aware使用Spring底层组件

    • 自定义组件想要使用Spring容器底层的一些组件(如:ApplicationContext,BeanFactory,xxx)只要自定义组件实现xxxAware

    • 在创建对象的时候,会调用接口规定的方法注入相关组件,把Spring底层一些组件注入到自定义的Bean中

    • xxxAware:对应功能使用xxxProcessor

      ApplicationContextAware==>ApplicationContextAwareProcessor

      实现过程在BeanPostProcessor后置处理器中

    使用不同的底层组件

    @Component
    public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware {
    	
    	private ApplicationContext applicationContext;
    
    	//使用IOC
    	@Override
    	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    		// TODO Auto-generated method stub
    		System.out.println("传入的ioc:"+applicationContext);
    		this.applicationContext = applicationContext;
    	}
    	
    	//使用BeanName
    	@Override
    	public void setBeanName(String name) {
    		// TODO Auto-generated method stub
    		System.out.println("当前bean的名字:"+name);
    	}
    
    	//使用EmbeddedValueResolve解析组件
    	@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:Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;

    环境:开发环境、测试环境、生产环境,分别对应:
    数据源:devDataSource、testDataSource、prodDataSource

    @Profle:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件

    • 标注
      1. 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
      2. 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
      3. 没有标注环境标识的bean,在任何环境下都是加载的;
    • 使用
      1. 如果对Bean标注了@Profile("default"),即使不激活,也默认使用此环境。即使标注了,如果没有对应的环境则都不激活,除了"default"
      2. 在启动时添加VM参数-Dspring.profiles.active=test,会使用此环境
      3. 不使用有参的AnnotationConfigApplicationContext创建ioc,使用无参构造器,在注册配置类之前设置激活环境。
      4. [SpringBoot]在类上使用注解@ActiveProfiles("test")激活

    创建多种数据源环境匹配不同数据库

    //使用多种方法读取properties配置文件信息
    //第一种方法读取配置文件
    @PropertySource("classpath:/dbconfig.properties")
    @Configuration
    public class MainConfigOfProfile implements EmbeddedValueResolverAware{
    	
    	//第二种方法读取配置文件
    	@Value("${db.user}")
    	private String user;
    	
    	private StringValueResolver valueResolver;
    	
    	private String  driverClass;
    	
    	//普通的Bean,任何时候都可以加载进容器
    	@Bean
    	public Yellow yellow(){
    		return new Yellow();
    	}
    	
    	//测试环境标识
    	@Profile("test")
    	//@Profile("default")
    	@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}");
    	}
    
    }

    测试

    //激活环境
    public class IOCTest_Profile {
    	
    	//1、使用命令行动态参数: 在虚拟机参数位置加载 -Dspring.profiles.active=test
    	//2、代码的方式激活某种环境;
    	@Test
    	public void test01(){
            //1、创建一个applicationContext
    		AnnotationConfigApplicationContext applicationContext = 
    				new AnnotationConfigApplicationContext();
    		//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);
    		}
    		
    		//普通Bean不受影响,一直可用
    		Yellow bean = applicationContext.getBean(Yellow.class);
    		System.out.println(bean);
    		applicationContext.close();
    	}
    }

    输出

    devDataSource
    com.atguigu.bean.Yellow@1ab3a8c8

    __EOF__

  • 本文作者: 蔚然丶丶
  • 本文链接: https://www.cnblogs.com/wei-ran/p/16203112.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    网页设计成品DW静态网页Html5响应式css3——电影网站bootstrap制作(4页)
    docker mysql8.0 启动,挂数据卷,定时备份,恢复~
    C51单片机使用1-工程创建和Led闪烁灯
    理解Java泛型的复杂写法<? super T>,<? extend T>
    【异常】springboot集成@Cacheable缓存乱码的问题解决方案
    [AGC041F] Histogram Rooks(神仙题 网格 容斥计数)
    CocosCreator3.8研究笔记(二十)CocosCreator UI组件(四)
    阿里一面:Kafka与RocketMQ区别是什么
    C++常见面试题汇总
    走进人工智能| 智能物联网 AIoT的魅力交织
  • 原文地址:https://www.cnblogs.com/wei-ran/p/16203112.html