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

2023-05-16

Spring注解开发

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

Spring注解开发_自定义注册组件、属性赋值、自动装配
Spring注解开发_Bean生命周期及执行过程
Spring注解开发_AOP原理及完整过程分析(源码)
Spring注解开发_声明式事务及原理
Spring注解开发_简单理解BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor、ApplicationListener
Spring注解开发_Spring容器创建概述
Spring注解开发_Servlet 3.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了,相当于配置文件中的<bean id=“” class=“”/>
  • @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<String, Person> 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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring注解开发_自定义注册组件、属性赋值、自动装配 的相关文章

  • python之collections

    collections是日常工作中的重点 高频模块 xff0c 包含了一些特殊的容器 xff0c 针对Python内置的容器 xff0c 例如list dict set和tuple xff0c 常用类型有 xff1a namedtuple
  • git 指定下载文件,目录

    1 创建路径 mkdir gitfile cd lt 路径 gt eg xff1a cd home gitfile 2 创建一个空的本地仓库 git init 3 连接远程仓库GitHub git remote add f origin l
  • Ubuntu v4l2 视屏流花屏问题

    之前用的好好解析YUV xff0c MJPEG 换了个核心板就不好使了 xff0c opencv3 4 6 gt gt gt opencv4 5 5 xff0c Mat xff0c cvMat xff0c IplImage 的类型转换也不好
  • qt qmake .qrc hasmodification time xxx in the future

    原因 xff1a 跨平台生成的 qrc 文件创建时间与目标平台时间不一致导致 xff0c 如win写的 copy 到 Linux xff0c 再编译可能会遇到该bug 导致无法qmake 与 build 解决 xff1a touch qrc
  • (转)python图像操作

    转自 xff1a zbxzc 侵删 使用PIL完成 python view plain copy span class hljs keyword import span Image span class hljs comment 打开图像
  • 关于input to reshape is a tensor 的问题

    span class hljs keyword for span index name span class hljs operator in span enumerate classes class path 61 cwd 43 name
  • mobileNet训练自己的样本

    span class hljs keyword import span matplotlib pyplot span class hljs keyword as span plt span class hljs keyword import
  • 关于屏幕适配之比例布局

    对于平板等需求场合 xff0c 它们的屏幕比例以16 xff1a 10和16 xff1a 9等为主 xff0c 但是屏幕尺寸各异 xff0c 分辨率各异 xff0c 即便是同一尺寸也有多种分辨率 xff0c 这种时候无论是使用dp还是px
  • 机器学习实战:ValueError: invalid literal for int() with base 10: '0.000000'

    在logistic回归一章中 xff0c 在将训练数据转换为int型时 xff0c 会出现日下报错 xff1a ValueError invalid literal for int with base 10 0 000000 只需将下面一句
  • cuda-8.0安装心得

    cuda 8 0安装 xff08 这两天不小心把原来的显卡驱动搞崩 xff0c 挣扎了好久 xff0c 只好重新走一遍 xff09 cuda 安装条件 gcc5 3 0 xff08 版本不能太高 xff09 sudo apt get ins
  • 在GPU刨过的坑

    这两天回学校这两天先是把自己的linux系统给强制删除了 xff0c 然后导致重启无法正常引导进入win xff0c 最后win也救不活了 xff0c 还不好重装系统 xff0c 各种文件损坏 xff0c 简单粗暴的翻车血泪史 捷径路上总是
  • [ArchLinux] 搜狗拼音输入法的安装

    配置源 在ArchlinuxCN源中有很多方便中国用户使用的包 xff0c 其中也包含了经常使用的搜狗拼音输入法 xff0c 于是我们需要先配置ArchlinuxCN源 xff0c 这样我们就可以使用自带的包管理器Pacman直接安装搜狗拼
  • [ArchLinux] 安装及KDE桌面环境安装配置

    ArchLinux 安装及KDE桌面环境安装配置 首先 xff0c 安装之前 xff0c 需要一个 启动介质 xff0c 我这里习惯使用USB设备作为启动介质 xff0c 这是由于ArchLinux滚动更新的特性 xff0c 而且占用空间很
  • 使用crontab执行定时任务时加flock独占锁防止进程堆积

    使用crontab执行定时任务 此处为每分钟执行一次 加flock独占锁防止进程堆积 注意给 var run 读写权限 xff0c 或者放到一个有读写权限的文件夹 span class token operator span span cl
  • macOs 安装liplpcap

    1 xff0c 下载liplpcap http www tcpdump org 1 在tcpdump网站下载libpcap的latest release 2 tar zxvf 3 configure make amp make instal
  • Android应用开发常用知识(4)

    Android string 中product的使用 Android的资源文件string xml会出现下面同名的字符串 xff1a lt string name 61 34 build type 34 product 61 34 tv 3
  • VR行业的发展现状和前景

    5G技术的应用推广 xff0c 加速推动虚拟现实不断发展和完善 xff0c VR产业迅速在各个领域和行业都得到广泛应用 xff0c 最好直观的感受就是知觉体验得到了良好的增强作用 本文的主要内容是简单概括VR技术的发展现状和发展前景 一 V
  • org.apache.ibatis.annotations不存在

    今天遇到了一个很有意思的bug 有人 xff08 还不止一个人 xff09 来问我 xff0c 为什么项目启动不了 xff0c 我说不可能啊 xff0c 我这不跑得好好的吗 xff0c 而且成功启动的也不止我一个啊 然后他就说 xff0c
  • 【学习笔记】Ubuntu双系统+搭建个人服务器

    Ubuntu双系统 43 搭建个人服务器 前言1 Ubuntu 43 Win双系统1 1 制作U盘启动盘1 2 系统分盘1 3 安装Ubuntu系统 2 搭建个人服务器2 1 设置root2 2 配置ssh2 3 向日葵连接 3 内网穿透3
  • (原创)开发微信公众平台遇到的乱码等问题的解决

    1 ngrok内网映射问题 首先这个工具是外国人写的 服务器也在国外 但是tunnel部属在国内 支持ngrok绝大多数功能 http www tunnel mobi 命令行中使用方法 在CMD命令中先切换到ngrok所在的位置再进行如下操

随机推荐

  • iOS给应用添加支持的文件类型/根据文件类型打开应用

    iOS给应用添加支持的文件类型 根据文件类型打开应用 之前写过类似的文章 IOS UTI 统一类型标识符 根据文件后缀打开APP 和 自定义UTI 注册你的APP所支持的文件类型 这里 再次总结说明 已经存在的UTL类型 苹果官方文档提供了
  • 编程之美 -- 中国象棋将帅问题

    下过中国象棋的朋友都知道 xff0c 双方的 将 和 帅 相隔遥远 xff0c 并且它们不能照面 在象棋残局中 xff0c 许多高手能利用这一规则走出精妙的杀招 假设棋盘上只有 将 和 帅 二子 xff08 为了下面叙述方便 xff0c 我
  • C++单元测试工具 -- CppUnit

    CppUnit 作为C 43 43 语言的一款测试工具 xff0c 其实也是一个开源项目 xff0c 与JUnit一样 xff0c 用来方便开发人员进行单元测试的工具 项目地址 xff1a http sourceforge net apps
  • 拒绝游戏!发愤图强!

    立帖为证 xff01 xff01 xff01
  • C++ STL — 第6章 STL容器(二)deque

    C 43 43 STL容器deque和vector很类似 xff0c 也是采用动态数组来管理元素 使用deque之前需包含头文件 xff1a include lt deque gt 它是定义在命名空间std内的一个class templat
  • C++ STL — 第6章 STL容器(三)list

    一 list基础 List使用一个双向链表来管理元素 图一显示了list的结构 图一 list的结构 任何型别只要具备赋值和可拷贝两种性质 xff0c 就可以作为list的元素 二 list的功能 list的内部结构和vector和dequ
  • STL list remove和sort函数

    include lt iostream gt include lt list gt include lt iterator gt using namespace std bool cmp int a int b return a gt b
  • 排序 -- 简单选择排序

    选择排序 思想 xff1a 每一趟 n i 43 1 xff08 i 61 1 2 3 n 1 xff09 个记录中选择关键字最小的记录作为有序序列的第i个记录 简单选择排序 xff1a 通过n i次关键字间的比较 xff0c 从n i 4
  • HDOJ 1106 排序

    题目地址 xff1a http acm hdu edu cn showproblem php pid 61 1106 Problem xff1a 输入一行数字 xff0c 如果我们把这行数字中的 5 都看成空格 xff0c 那么就得到一行用
  • ftp创建文件权限问题

    一 问题 有一个这样的需求 xff0c admin为一个Linux为其FTP应用创建的一个有权限限制的用户 xff0c 通过admin用户可以进行登录FTP服务 xff0c 登录FTP服务后 xff0c 创建文件夹 xff0c 该文件夹的用
  • lottie加载动画,第一次有延迟问题

    lottie是airbnb推出的一个直接将AE工程转化为动画的工具 ae project gt data json gt LottieComposition gt Lottie动画 之前做一个比较复杂的动画 xff0c 花了两天时间都在画各
  • CentOS 7防火墙快速开放端口配置方法

    CentOS 7防火墙快速开放端口配置方法 这篇文章主要为大家详细介绍了CentOS 7防火墙开放端口的快速方法 xff0c 感兴趣的小伙伴们可以参考一下 一 CentOS 7快速开放端口 xff1a CentOS升级到7之后 xff0c
  • C语言unsigned char、char与int之间的转换

    C语言unsigned char char与int之间的转换 2016年10月23日 18 40 50 bladeandmaster88 阅读数 xff1a 11347更多 个人分类 xff1a c语言基础 先来看一道题 xff1a cha
  • Android 内存分析(java/native heap内存、虚拟内存、处理器内存 )

    1 jvm 堆内存 dalvik 堆内存 不同手机中app进程的 jvm 堆内存是不同的 xff0c 因厂商在出厂设备时会自定义设置其峰值 比如 在Android Studio 创建模拟器时 xff0c 会设置jvm heap 默认384m
  • RabbitMq(一) RabbitMq工作模型

    RabbitMq工作模型 Mq基础RbbitMq工作模型RabbitMq基本使用原生apiSpring集成Springboot集成 RabbitMq进阶知识订单延迟关闭队列满了 总结 Mq基础 message queue 消息队列 特点 x
  • SSM整合_实现增删改查_基础环境搭建

    写在前面 SSM整合 年轻人的第一个增删改查 基础环境搭建 SSM整合 年轻人的第一个增删改查 查找 SSM整合 年轻人的第一个增删改查 新增 SSM整合 年轻人的第一个增删改查 修改 SSM整合 年轻人的第一个增删改查 删除 GitHub
  • SSM整合_实现增删改查_查找

    写在前面 SSM整合 年轻人的第一个增删改查 基础环境搭建 SSM整合 年轻人的第一个增删改查 查找 SSM整合 年轻人的第一个增删改查 新增 SSM整合 年轻人的第一个增删改查 修改 SSM整合 年轻人的第一个增删改查 删除 GitHub
  • SSM整合_实现增删改查_新增

    写在前面 SSM整合 年轻人的第一个增删改查 基础环境搭建 SSM整合 年轻人的第一个增删改查 查找 SSM整合 年轻人的第一个增删改查 新增 SSM整合 年轻人的第一个增删改查 修改 SSM整合 年轻人的第一个增删改查 删除 GitHub
  • 解决关机蓝屏 | MULTIPLE_IRP_COMPLETE_REQUESTS | klflt.sys

    已经解决蓝屏问题 xff0c 原因是卡巴斯基安全软件驱动导致 xff0c 需要卸载卡巴斯基安全软件 xff0c 详细过程如下 一 关机时蓝屏 Win10系统 xff0c 在关机动画快结束时突然蓝屏 xff0c 提示 xff1a 你的设备遇到
  • Spring注解开发_自定义注册组件、属性赋值、自动装配

    Spring注解开发 浅尝Spring注解开发 xff0c 基于Spring 4 3 12 包含自定义扫描组件 自定义导入组件 手动注册组件 自动注入方法和参数 使用Spring容器底层组件等 Spring注解开发 自定义注册组件 属性赋值