12-Spring自动装配-方法、构造器装配,Aware注入Spring底层组件

  • Post author:
  • Post category:其他




构造器位置的自动装配

@Autowired 注解支持添加到: 构造器、参数、方法、属性上.

默认注入到 IOC 容器中的组件,容器启动会调用无参构造创建对象,再进行赋值操作,当我们注入对象时,可以写一个有参构造器,加上@Autowired,实现对象的自动注入.

/**
 * @author Demon-HY
 * @date 2019-12-12
 */
@Service
public class UserService {

    private final UserDao userDao;

    // 1. 当前对象如果只有一个有参构造器,可以省略 @Autowired 注解
    // 2. @Autowired 可以直接加在参数上: public UserService(@Autowired UserDao userDao)
    @Autowired
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public String toString() {
        return "UserService{" +
                "userDao=" + userDao +
                '}';
    }
}



方法位置的自动装配

在配置类中注入@Bean时,实现注入

/**
 * @author Demon-HY
 * @date 2019-12-12
 */
public class UserService {

    private final UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public String toString() {
        return "UserService{" +
                "userDao=" + userDao +
                '}';
    }
}
/**
 * @author Demon-HY
 * @date 2019-12-24
 */
@Configuration
@ComponentScan(value = "com.demon")
public class ConfigOfAutowired {

    // @Bean 标注的方法创建对象时,方法参数的值从容器中获取,
    // 所以这里的UserDao 可以添加 @Autowired, 也可以不添加,他都会从容器中查询
    @Bean
    public UserService userService(UserDao userDao) {
        return new UserService(userDao);
    }
}



实现Aware注入Spring底层组件

Spring 给我们提供了一些可以注入Spring 底层组件的类,具体有哪些可以看一下 Aware 接口的实现类.

比较常见的有:

  • ApplicationContextAware: Spring 上下文
  • EnvironmentAware: Spring 环境变量
  • BeanName: 对象名
  • EmbeddedValueResolverAware: 解析String中的占位符

编写一个测试类:

package com.demon;

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.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.util.StringValueResolver;

/**
 * @author Demon-HY
 * @date 2020-1-8
 */
@Service
public class TestAware implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware, EnvironmentAware {

    private ApplicationContext applicationContext;
    private String beanName;
    private StringValueResolver resolver;
    private Environment environment;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("对象名: " + name);
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.resolver = resolver;
        format();
    }

    // 测试 StringValueResolver
    private void format() {
        System.out.println(this.resolver.resolveStringValue("当前系统版本: ${os.name}"));
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
        System.out.println("获取系统设置: " + environment.getProperty("os.name"));
    }

    @Override
    public String toString() {
        return "TestAware{" +
                "applicationContext=" + applicationContext +
                ", beanName='" + beanName + '\'' +
                ", resolver=" + resolver +
                '}';
    }
}

写一个测试类看下效果:

/**
 * @author Demon-HY
 * @date 2019-12-9
 */
public class IOCTestAutowired {

    @Test
    public void test() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigOfAutowired.class);

        TestAware testAware = context.getBean(TestAware.class);
    }
}

# 打印
对象名: testAware
获取系统设置: Windows 7
当前系统Windows 7

每一个Aware都有一个对应的后置处理器去完成赋值操作,比如 ApplicationContextAwareProcessor, 这些后置处理器命名一般为: XXXProcessor.



Aware 接口实现原理

我们在上面例子的 setEnvironment() 方法里面打一个断点,这样可以看到完整的调用栈,可以看到下面这段代码:

// AbstractAutowireCapableBeanFactory.initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd);

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    // 判断是否有当前类的访问权限
	if (System.getSecurityManager() != null) {
		AccessController.doPrivileged(new PrivilegedAction<Object>() {
			@Override
			public Object run() {
				invokeAwareMethods(beanName, bean);
				return null;
			}
		}, getAccessControlContext());
	}
	else {
	    // 创建 bean实例
		invokeAwareMethods(beanName, bean);
	}

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
	    // TODO 这里就是对 bean 实例中实现的那些Aware接口设置属性值的方法
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	try {
	    // 给 bean 的属性赋值
		invokeInitMethods(beanName, wrappedBean, mbd);
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				(mbd != null ? mbd.getResourceDescription() : null),
				beanName, "Invocation of init method failed", ex);
	}

	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}
	return wrappedBean;
}

看名字就知道,这个方法是Bean实例初始化方法, 里面的 applyBeanPostProcessorsBeforeInitialization() 方法就是对 bean 实例中实现的那些Aware接口设置属性值的方法,继续看这个方法的实现:

// AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName);

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
		throws BeansException {

	Object result = existingBean;
	// getBeanPostProcessors() 方法获取了所有Spring支持的后置处理器
	for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
	    // TODO 循环遍历调用后置处理器方法
		result = beanProcessor.postProcessBeforeInitialization(result, beanName);
		if (result == null) {
			return result;
		}
	}
	return result;
}

上面这个方法只是获取了所有的后置处理器,并循环去调用,检查bean有没有需要处理的数据,继续看postProcessBeforeInitialization()方法:

// ApplicationContextAwareProcessor.postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException;

@Override
	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
		AccessControlContext acc = null;

        // 检查 bean 操作权限
		if (System.getSecurityManager() != null &&
				(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
						bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
						bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
			AccessController.doPrivileged(new PrivilegedAction<Object>() {
				@Override
				public Object run() {
					invokeAwareInterfaces(bean);
					return null;
				}
			}, acc);
		}
		else {
		    // TODO 这里就是实际调用后置处理器设置bean属性的方法
			invokeAwareInterfaces(bean);
		}

		return bean;
	}

看到这里就知道了,Spring会去判断 bean 有没有实现对应的接口

继续看 invokeAwareInterfaces() 方法:

// ApplicationContextAwareProcessor.invokeAwareInterfaces(Object bean);

private void invokeAwareInterfaces(Object bean) {
    // 判断 bean 是否有实现对应的接口
	if (bean instanceof Aware) {
		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);
		}
	}
}

看到上面的代码,也就很清楚的知道Spring 目前支持的Aware都有哪些了.



咖啡小馆

QQ群:

823971061

点击按钮入群



版权声明:本文为u014186972原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。