Spring annotation-driven: attribute assignment, automatic assembly, @Profile environment construction

Attribute assignment

package jane.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;

public class Person
{
    
    
	/*
	 * 使用@Value赋值可以写的有:
	 * 1.基本数值,字符串
	 * 2.可以写SPEL表达式:#{}
	 * 3.可以写${},用来取出配置文件或运行环境变量中的值
	 * 		按照之前xml来写配置文件,应该是加载资源文件然后${}来获取值
	 * 			<context:property-placeholder location="classpath:person.properties"/>
	 * 		现在也差不多按照之前的步骤
	 * 			在配置类里面加上相应的注解
	 * 				@PropertySource(value = {"classpath:person.properties"})
	 */
	@Value("张三")
	private String name;
	@Value("#{16+2}")
	private Integer age;
	@Value("${person.lastname}")
	private String lastname;
	//省略get和set方法
	@Override
	public String toString()
	{
    
    
		return "Person [name=" + name + ", age=" + age + ", lastname=" + lastname + "]";
	}
	public Person(String name, Integer age)
	{
    
    
		super();
		this.name = name;
		this.age = age;
	}
	public Person()
	{
    
    
		super();
	}
	
}

Configuration class

package jane.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import jane.bean.Person;

@PropertySource(value = {
    
    "classpath:person.properties"})
@Configuration
public class MyConfig4
{
    
    
	@Bean
	public Person person()
	{
    
    
		return new Person();
	}
}

Automatic assembly

Configuration class

package jane.config;

import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import jane.bean.Person;
import jane.dao.BookDao;

/*
 * 自动装配:
 * 		就是spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
 * 方法有:
 * 1)@Autowired:自动注入
 * 		1.默认优先按照类型去容器中找对应的组件
 * 		2.如果按照类型找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找
 * 		3.@Qualifier("bookDao2"):使用@Qualifier指定需要装配的组件的id,
 * 					而不是使用属性名,这个@Qualifier注解写在需要自动装配的属性上
 * 		4.自动装配默认是一定要将属性赋值完成的,没有就会报错
 * 			可以使用@Autowired(required = false),这样就不一定要赋值了
 * 		5.@Primary:让spring进行自动装配的时候,默认使用首选的bean,
 * 			而且这个注解是标注在bean上面的
 * 			不过也可以继续使用@Qualifier指定需要装配的bean的名字
 * 2)spring还支持使用@Resource(JSR250定义)和Inject(JSR330)(都是java规范的注解)
 * 		@Resource:
 * 			可以和@Autowired一样实现自动装配功能,默认是按照组件名称进行装配的
 * 			但是不能支持@Primary和@Autowired(required=false)
 * 		@Inject:
 * 			需要导入javax.inject的包,和Autowired的功能一样,
 * 			没有required=false功能,其他的都有
 * 	@Autowired是spring定义的,@Resource,@Inject是java定义的
 * AutowiredAnnotationBeanPostProcessor:解析自动装配功能
 * 3)@Autowired还可以标注在构造器,参数,方法,属性上面,这样都是从容器中获取参数组件的值
 * 		1.标注在方法上,spring容器创建当前对象就会调用方法,完成赋值
 * 				方法里面传入的参数,自定义类型的值就会从ioc容器中获取
 * 				@Bean+方法参数,参数是从容器中获取(这里参数中省略了@Autowired注解)
 * 		2.标注在构造器上面,构造器需要的组件也是从容器中获取
 * 			如果组件只有一个有参构造器,那么就只能使用这个构造器进行创建对象
 * 				这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取
 * 		3.标在参数位置
 * 4)自定义组件想要使用spring底层的一些组件(比如ApplicationContext,BeanFactory,...)
 * 	 那么就需要自定义组件实现xxxAware接口,这样在创建对象的时候,就会调用接口规定的方法注入相关的组件
 * 	 这样就是把spring底层一些组件注入到自定义的bean之中
 * 	 xxxAware接口的功能都是借助xxxProcessor,
 * 	 比如ApplicationContextAware就是借助ApplicationContextAwareProcessor
 */
@PropertySource(value = {
    
    "classpath:person.properties"})
@Configuration
@ComponentScan({
    
    "jane.dao","jane.service","jane.controller","jane.bean"})
public class MyConfig4
{
    
    
	@Bean
	public Person person()
	{
    
    
		return new Person();
	}
	@Primary
	@Bean("bookDao2")
	public BookDao bookDao()
	{
    
    
		BookDao bookDao = new BookDao();
		bookDao.setLable("2");
		return bookDao;
	}
}

bean class

package jane.dao;

import org.springframework.stereotype.Component;

@Component
public class BookDao
{
    
    
	private String lable="1";

	public String getLable()
	{
    
    
		return lable;
	}

	public void setLable(String lable)
	{
    
    
		this.lable = lable;
	}

}

package jane.service;

import javax.annotation.Resource;
import javax.inject.Inject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import jane.dao.BookDao;

@Service
public class BookService
{
    
    
//	@Qualifier("bookDao2")
	@Autowired(required = false)
//	@Resource
//	@Inject
	private BookDao bookDao;
	
//	@Autowired
	public BookService(BookDao bookDao)
	{
    
    
		this.bookDao=bookDao;
		System.out.println("BookService有参构造器");
	}
//	public BookService(@Autowired BookDao bookDao)
//	{
    
    
//		this.bookDao=bookDao;
//		System.out.println("BookService有参构造器");
//	}
	
//	@Autowired
	public void setBookDao(BookDao bookDao)
	{
    
    
		this.bookDao = bookDao;
	}
	public BookDao getBookDao()
	{
    
    
		return bookDao;
	}

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

package jane.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import jane.service.BookService;

@Controller
public class BookController
{
    
    
	@Autowired
	private BookService bookService;
}

A bean that implements the xxxAware interface

package jane.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;

@Component
public class ExampleAware implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware
{
    
    
	//这个接口是得到IOC容器对象
	ApplicationContext applicationContext;
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
	{
    
    
		this.applicationContext=applicationContext;
		System.err.println("传进来的"+applicationContext);
	}
	//这个是得到当前bean的id
	@Override
	public void setBeanName(String name)
	{
    
    
		System.err.println("当前bean的名字:    "+name);
	}
	//这个是得到容器的字符串的解析器,能解析${}和#{}之类的值
	@Override
	public void setEmbeddedValueResolver(StringValueResolver resolver)
	{
    
    
		String resolveStringValue = resolver.resolveStringValue("解析的${os.name},岁数#{10+8}");
		System.err.println(resolveStringValue);
	}
}

Original code view xxxAware working principle

First of all, the breakpoint is here.
Insert picture description here
Check the first few parts of the breakpoint, especially the ApplicationContextAware.
Here, the ApplicationContextAwareProcessor first determines whether the bean implements one of the many interfaces of xxxAware. It
happens that we meet the bean instanceof ApplicationContextAware
and then determine some permissions and the like, and finally execute invokeAwareInterfaces (bean);
Insert picture description here
Follow up with invokeAwareInterfaces to
find the core sentence. ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
Turn the bean into a parent interface, and then call the method of the parent interface. The actual method used is the overloaded method of the implementation class (that is, the bean)
Insert picture description here

@Profile environment setup

Configuration class

package jane.config;

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;
import com.mchange.v2.c3p0.ComboPooledDataSource;

/*
 * Profile:
 * 		spring为我们提供的可以根据当前环境动态地激活和切换一系列组件的功能
 * 比如现在的环境:
 * 			  开发环境,测试环境,生产环境
 * 数据源对应:(A)      (B)      (C)
 * 
 * @Profile("")指定该组件在哪一个环境的情况下才能被注册到容器中,
 * 如果这个组件没有指定的话,如何环境下都是能注册这个组件的
 * 
 * 如果某个组件加了环境标识,那么只有这个环境被激活的时候才会被注册到容器中
 * 		默认是使用default环境
 * 
 * @Profile("")如果是写在配置类上面,那么就只有是指定的环境的时候,
 * 整个配置类里面的所有配置才能开始生效
 * 
 * 切换环境的方法:
 * 1.使用命令行的动态参数,在run configurations里面的Arguments的VM arguments
 * 		写上参数-Dspring.profiles.active=test
 * 2.使用代码的方式:
 * 	点进AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig5.class);
 * 发现有参构造器会直接注册容器并且直接刷新容器
		  public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) 
		  {
				this();
				register(annotatedClasses);
				refresh();
		   }
	所以我们得使用无参构造器,步骤是:
	创建applicationcontext,设置需要激活的环境
	注册主配置类,启动刷新容器
		AnnotationConfigApplicationContext applicationContext1 = new AnnotationConfigApplicationContext();
		applicationContext1.getEnvironment().setActiveProfiles("test","dev");
		applicationContext1.register(MyConfig5.class);
		applicationContext1.refresh();
 */
@PropertySource("classpath:/db.properties")
@Configuration
public class MyConfig5 implements EmbeddedValueResolverAware
{
    
    
	@Value("${db.user}")
	private String user;
	private String driverClass;
	private StringValueResolver ValueResolver;
	
	@Profile("test")
	@Bean("testDataSource")
	public DataSource dataSourceTest(@Value("${db.password}")String password) throws Exception
	{
    
    
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(password);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/shop?serverTimezone=GMT%2B8");
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
	
	@Profile("dev")
	@Bean("DevDataSource")
	public DataSource dataSourceDev(@Value("${db.password}")String password) throws Exception
	{
    
    
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(password);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8");
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
	
	@Profile("prod")
	@Bean("ProdDataSource")
	public DataSource dataSourceProd(@Value("${db.password}")String password) throws Exception
	{
    
    
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(password);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/work?serverTimezone=GMT%2B8");
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
	@Override
	public void setEmbeddedValueResolver(StringValueResolver resolver)
	{
    
    
		this.ValueResolver=resolver;
		driverClass = ValueResolver.resolveStringValue("${db.driverClass}");
	}
}

Test class

	@org.junit.Test
	public void test3()
	{
    
    
//		AnnotationConfigApplicationContext applicationContext1 = new AnnotationConfigApplicationContext();
//		applicationContext1.getEnvironment().setActiveProfiles("test","dev");
//		applicationContext1.register(MyConfig5.class);
//		applicationContext1.refresh();
		
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig5.class);
//		Map<String, DataSource> beansOfType = applicationContext.getBeansOfType(DataSource.class);
//		System.out.println(beansOfType);
		String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
		for (String string : beanNamesForType)
		{
    
    
			System.out.println(string);
		}
	}

resource

db.user=root
db.password=1234
db.driverClass=com.mysql.cj.jdbc.Driver

Guess you like

Origin blog.csdn.net/qq_43416157/article/details/108289719