一、Bean 的注入
@Configuration
@Import({User.class, ImportSelectorDemo.class, ImportBeanDefinitionRegistrarImpl.class}) // id 默认为 User 的全类名
public class SpringConfig {
/**
* 容器添加组件的方式
* 1.component-scan + @Controller/@Service/@Repository/@Component
* 2.@Bean
* 3.@Import
* a.@Import({User.class}) // id 默认为 User 的全类名
* b.@Import({ImportSelectorImpl.class}) // 将 ImportSelectorImpl::selectImports 返回值导入容器
* c.@Import({ImportBeanDefinitionRegistrarImpl.class}) // 使用
* ImportBeanDefinitionRegistrar::registerBeanDefinitions 自行注入 bean
* 4.使用 FactoryBean
* a.需要将 FactoryBean 加入容器才能使该 FactoryBean 生效
* b.通过 FactoryBean 的 ID 值获取到的 Bean 对象为 FactoryBean::getObject 创建的对象
* 如果需要获取 FactoryBean 本身,需要在 FactoryBean 的 ID 值前加前缀 "&"
*/
@Bean(value = "person")
public Person getPerson() {
return new Person(1, "Lee", 53);
}
@Bean
public UserFactoryBean userFactoryBean() {
return new UserFactoryBean();
}
}
// 使用 @Import({ImportSelectorImpl.class}) 注入组件
public class ImportSelectorImpl implements ImportSelector {
/**
* @param importingClassMetadata 使用该 ImportSelector 的类的所有注解信息
* @return 需要导入到容器中的所有组件的全类名
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.blackpearl.entities.Color"};
}
}
// 使用 @Import({ImportBeanDefinitionRegistrarImpl.class}) 注入组件
public class ImportBeanDefinitionRegistrarImpl implements ImportBeanDefinitionRegistrar {
/**
* @param importingClassMetadata 使用该 ImportBeanDefinitionRegistrar 的类的所有注解信息
* @param registry 使用 registry.registerBeanDefinition 手动注册 bean
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(Red.class);
registry.registerBeanDefinition("red", beanDefinition);
}
}
/**
* FactoryBean<T> 范性的类型即为需要加入容器的组件类型
*/
public class UserFactoryBean implements FactoryBean<User> {
/**
* 返回一个 User 对象并加入容器
* 使用 FactoryBean<T>::getObject 注入容器
*/
@Override
public User getObject() throws Exception {
return new User("admin", "admin");
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
二、Bean 的生命周期
1、自定义 Bean 对象的 init / destroy 方法
/**
* Bean 的生命周期大致概括为
* Bean 创建 => Bean 初始化 => Bean 销毁
* 根据 Bean 的 Scope 不同,Bean 的创建时机也不相同,Spring 支持自定义 Bean 的初始化和销毁方法
*
* 指定 Bean 的初始化和销毁方法
* 1.xml 中可以指定 init-method="" destroy-method="" 定制 Bean 的初始化和销毁方法
* 2.@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
* 3.让 Bean 对象 implements InitializingBean => 实现 Bean 初始化方法
* implements DisposableBean => 实现 Bean 销毁方法
* 4.给 Bean 对象中的方法标注 @PostConstruct => 实现 Bean 初始化方法
* 标注 @PreDestroy => 实现 Bean 销毁方法
*/
@ComponentScan(basePackages = {"com.blackpearl.entities"})
@Configuration
public class BeanLifeConfig {
class Car {
public void initMethod() {
System.err.println("Car::initMethod()");
}
public void destroyMethod() {
System.err.println("Car::destroyMethod()");
}
}
// 使用 @Bean 属性指定初始化和销毁方法
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public Car car() {
return new Car() ;
}
}
/**
* 使用 InitializingBean::afterPropertiesSet => init-method
* 使用 DisposableBean::destroy => destroy-method
*/
@Component
public class Cat implements InitializingBean, DisposableBean {
@Override
public void destroy() throws Exception {
System.err.println("Cat::destroy()");
}
// 初始化方法
@Override
public void afterPropertiesSet() throws Exception {
System.err.println("Cat::afterPropertiesSet()");
}
}
/**
* 使用 @PostConstruct => init-method
* 使用 @PreDestroy => destroy-method
*/
@Component
public class Dog {
@PostConstruct
public void initMethod() {
System.err.println("Dog::initMethod()");
}
@PreDestroy
public void destroyMethod() {
System.err.println("Dog::destroyMethod()");
}
}
2、interface BeanPostProcessor
1、使用方式
/**
* Bean 的生命周期:
* Bean 的构造(Bean 对象创建)
* 单实例:容器启动时创建 Bean
* 多实例:每次获取时创建对象
*
* BeanPostProcessor::postProcessBeforeInitialization
*
* Bean 的初始化:
* 对象创建完成并完成赋值,调用指定的 Bean 初始化方法
*
* BeanPostProcessor::postProcessAfterInitialization
*
* Bean 的销毁:
* 单实例:容器销毁时执行指定的 Bean 销毁方法
* 多实例:不会调用销毁方法
*
* 使用 interface BeanPostProcessor 的 postProcessBeforeInitialization => Bean 对象初始化方法执行之前执行
* postProcessAfterInitialization => Bean 对象初始化方法执行之后执行
*/
@Component
public class BeanPostProcessorImpl implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.err.println(beanName + " 对象自定义初始化方法之前执行");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.err.println(beanName + " 对象自定义初始化方法之后执行");
return bean;
}
}
2、原理解析
Bean 的创建流程位于 AbstractAutowireCapableBeanFactory::doCreateBean
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
// 如果 Bean 对象为单实例
if (mbd.isSingleton()) {
// 先尝试从缓存中获取
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 获取失败则执行 Bean 对象构造方法 => 创建 Bean 对象
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 为创建的 Bean 对象进行属性赋值
populateBean(beanName, mbd, instanceWrapper);
// 执行 Bean 对象的初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {}
// Register bean as disposable.
try {
// 将单实例 Bean 对象加入到 list 中,在容器销毁时会调用这个 list 中所有 Bean 对象的销毁方法
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {}
return exposedObject;
}
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
{
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 执行容器中所有的 BeanPostProcessor 执行其 postProcessBeforeInitialization 方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 执行 Bean 对象的初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {}
if (mbd == null || !mbd.isSynthetic()) {
// 执行容器中所有的 BeanPostProcessor 执行其 postProcessAfterInitialization 方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
}
三、Bean 的属性赋值
/**
* 使用 @PropertySource(value = {"***"}) 将外部配置文件中配置的 k:v 值加载保存至环境(Environment)变量中
* 加载完外部配置文件后可以使用 "${}" 获取其中的配置项的值
*/
@PropertySource(value = {"classpath:pig.properties"})
@Configuration
public class ValueConfig {
@Bean
public Pig pig() {
return new Pig();
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Pig {
// @Value 的 value 表达式支持 普通string / #{} / ${}
@Value(value = "#{20 - 3}")
private Integer id;
@Value(value = "乔治")
private String name;
@Value(value = "${pig.age}")
private Integer age;
}
四、Bean 的自动装配
1、@Autowired / @Resource / @Inject
@Controller
public class ControllerDemo {
/**
* 使用 @Autowired 进行自动注装配组件
* 1.默认按照类型在容器中查找对应的组件 => applicationContext.getBean(UserService.class)
* 2.如果有多个类型相同的组件,则使用 属性名 作为 id 在容器中查找对应的组件 =>
* applicationContext.getBean("userService")
* 3.使用 @Autowired 自动注入组件默认必须注入成功,否则报错
* 使用 @Autowired(required = false) 修改为装配失败不报错
*
* 使用 @Qualifier(value = "***") 指定装配组件的 id 值
*
* 使用 @Primary 指定装配该类型的组件时,优先使用哪个组件进行注入
* @Qualifier 优先级大于 @Primary
* 即指定 @Qualifier,后者就会失效
*
* @Resource 和 @Inject 的功能和 @Autowired 类似均可以完成自动注入功能
* 1.@Resource 默认按 属性名 进行自动装配,不支持 @Primary 同时不支持 required 属性修改
* 2.@Inject 默认按 类型 进行自动装配的,不支持 required 属性修改
* 3.@Autowired => org.springframework.*** Spring 独有
* @Resource / @Inject => javax.*** javax 规范
*/
@Autowired
@Qualifier(value = "userService")
private UserService userService;
@Resource
private UserDao userDao;
@Inject
private PersonDao personDao;
}
- @Autowired 的使用
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public @interface Autowired {}
- ElementType.CONSTRUCTOR:构造器使用的方法参数默认会从容器中获取
容器中的 Bean 在容器启动会调用其无参构造器创建对象,再进行赋值操作
如果类只存在一个有参构造器,构造器的参数即使不指定 @Autowired 默认也会从容器中获取 - ElementType.METHOD:方法参数默认会从容器中获取
@Bean 标注的方法的方法参数即使不使用 @Autowired 同样会从容器中获取 - ElementType.PARAMETER:指定该参数的值需要从容器中获取
- ElementType.FIELD:自动将容器中的组件注入到该变量
2、自动装配 Spring 容器底层应用组件
自定义组件如果需要注入 Spring 容器底层组件,需要实现 ***Aware 接口,这些接口定义的方法会在 Bean 对象执行初始化方法之前执行,注入 Spring 容器底层应用组件
1、使用方式
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
private String username;
private String password;
/**
* BeanNameAware::setBeanName
* @param name 当前 Bean 在容器中的 name
*/
@Override
public void setBeanName(String name) {
System.err.println("class Red => " + name);
}
/**
* ApplicationContextAware::setApplicationContext
* @param applicationContext Spring 容器
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.err.println("Spring IOC => " + applicationContext);
}
/**
* EmbeddedValueResolverAware::setEmbeddedValueResolver
* @param resolver 表达式解析器,解析 #{} ${}
*/
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
System.err.println("ValueResolver => " + resolver);
}
}
2、原理解析
每一个 ***Aware 接口均会通过 ***Processor 在 Bean 执行初始化方法之前执行 ***Aware 接口定义的方法
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
// 如果 Bean 未 implements 这些 ***Aware 接口,直接返回
return bean;
}
// 否则执行 ***Aware 接口定义的方法
invokeAwareInterfaces(bean);
return bean;
}
/**
* 根据 Bean 对象 implements 的 Aware 接口的不同,执行其中的 set*** 方法传入 Spring 底层容器组件
*/
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
3、使用 @Profile 指定 Bean 的加载环境
@Profile 可以用于指定 Bean 对象被加载至 Spring 容器的环境,不指定 @Profile,默认在任何环境都会加载这个 Bean 对象
@Configuration
@Profile(value = {"default"})
public class SpringConfig {
/**
* 指定 @Bean 方法上的 @Profile(value = {"dev"}) 的 Bean 对象仅在环境满足的情况下进行加载
* 不指定则任何环境下均会加载该 Bean 对象
* 指定配置类上的 @Profile,类中的所有配置项仅在环境满足的情况下进行配置
*
* 如何切换环境:
* 1.使用虚拟机参数 -Dspring.profiles.active = ***
* 2.改变 Spring 容器配置类的获取方式
* AnnotationConfigApplicationContext applicationContext
* = new AnnotationConfigApplicationContext(SpringConfig.class);
* => AnnotationConfigApplicationContext applicationContext
* = new AnnotationConfigApplicationContext();
* applicationContext.getEnvironment().setActiveProfiles("dev");
* applicationContext.register(SpringConfig.class);
* applicationContext.refresh();
*/
@Profile(value = {"default"})
@Bean(value = "person")
public Person getPerson() {
return new Person(1, "Lee", 53);
}
@Profile(value = {"dev"})
@Bean
public User user() {
return new User();
}
}