说到Spring的核心功能,Spring AOP是始终绕不过去的一个点。而说到Spring AOP,开发中我们经常会用到这个功能,比如:日志记录、权限校验、事务管理等。我们也大概知道它基于动态代理实现的,那除了Spring AOP,Spring还有哪些地方使用到了动态代理?Spring中的动态代理又是如何实现的?让我们跟着这篇文章来一探究竟。
代理模式是23中设计模式中比较常见的一种设计模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。说简单点,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。通俗地来讲代理模式就是我们生活中常见的中介。
Java中一般使用代理在不改变目标类的基础,对类做增强处理。其实代理可以改变目标类,但是我们一般都不会去这样做,算是一种约定俗成的做法。
那我们就先来说说代理模式。代理模式分为静态代理和动态代理。
静态代理的应用场景:进行代码升级,例如,在原来的功能模块上添加新的功能,我们可以不用修改原来的底层代码,只需要通过代理模式来进行代码迭代。
例如:系统原来只是简单的实现了登录功能。
public class Service {
public void login(){
System.out.println("doLogin……");
}
}
第一次更新后,加入了权限校验模块。
public class CheckService extends Service{
private Service target;
public CheckService(Service target) {
this.target = target;
}
@Override
public void login() {
System.out.println("authentication……");
target.login();
}
}
第二次更新,增加了日志模块。
public class LogService extends Service{
private Service target;
public LogService(Service service) {
this.target = service;
}
@Override
public void login() {
System.out.println("print Logging……");
target.login();
}
}
系统更新后,只需要修改很少的主体代码就可以实现代码升级。
public static void main(String[] args) {
Service service = new Service();
// 第一次更新
Service checkService = new CheckService(service);
checkService.login();
// 第二次更新
Service loginService = new LogService(checkService);
loginService.login();
}
但更多的时候是,第二次更新时,第一次更新的就被舍弃了,随着系统的迭代,舍弃的代码会越来越多。
上面的代码可能表达的比较隐晦,我们使用下面的方式实现静态代理多一些。
public interface IService {
void process();
}
//实际处理类
public class TargetService implements IService {
public void process(){
System.out.println("TargetService ……");
}
}
public class ProxyService implements IService {
private IService target;
public ProxyService(IService target){
this.target = target;
}
public void process(){
System.out.println("before Proxy doing ……");
target.process();
System.out.println("after Proxy doing ……");
}
}
main(){
TargetService target = new TargetService();
ProxyService proxy = new ProxyService(target);
proxy.process();
}
优点:可以在不修改目标对象的前提下扩展目标对象的功能。
缺点:如果需要代理多个类,每个类都会有一个代理类,会导致代理类无限制扩展;如果类中有多个方法,同样的代理逻辑需要反复实现、应用到每个方法上,一旦接口或基类增加方法,目标对象与代理对象都要进行修改。
JDK动态代理原理:利用拦截器(必须实现InvocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。JDK动态代理是基于接口实现代理的,如果代理对象是类,那JDK无法进行代理。
JDK动态代理的一般步骤:
A.定义一个接口
B.创建InvocationHandler接口的实现类,实现invoke()方法。
C.调用Proxy.newProxyInstance()方法创建代理对象
public interface IService{
void process();
}
public class CoreService implements IService{
public void process(){
System.out.println("[target] CoreService's process()...");
}
}
public class JdkInvocationHandler implements InvocationHandler {
//目标类
private Object targetObj;
public JdkInvocationHandler(Object targetObj) {
this.targetObj = targetObj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
System.out.println("[JDK]method = " + name + ", args = " + Arrays.deepToString(args));
System.out.println("[JDK]mmethod: " + name + " before doing...");
//代理对象
Object returnValue = method.invoke(targetObj, args);
System.out.println("[JDK]mmethod: " + name + " after doing...");
return returnValue;
}
}
public class ProxyTest {
public static void main(String[] args) {
//目标类
CoreService coreService = new CoreService();
InvocationHandler jdkInvocationHandler = new JdkInvocationHandler(coreService );
IService proxyService = (IService)Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), new Class>[]{IService.class}, jdkInvocationHandler);
}
CGLIB动态代理原理:利用ASM框架,将代理对象类生成的class文件加载进来,通过修改其字节码生成子类完成对目标对象的代理。CGLIB既可以代理类,也可以代理接口。
CGLIB动态代理的一般步骤:
A.定义一个类
B.创建MethodInterceptor接口的实现类,实现intercept()方法。
C.创建CGLIB代理增强器Enhancer,通过其create()方法创建代理对象
public class Service{
pubilc void process(){
System.out.println("[target] class Service's process()...");
}
}
public class CustomerCglibMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
String methodName = method.getName();
System.out.println("method = " + methodName + " ,args= " + Arrays.deepToString(objects));
System.out.println("[CGLIB]method = " + methodName + " ,before doing... ");
// 代理对象
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("[CGLIB]method = " + methodName + " ,after doing... ");
return invoke;
}
}
main{
// 增强器
Enhancer enhancer = new Enhancer();
// 设置目标代理类
enhancer.setSuperclass(Service.class);
// 设置Interceptor
enhancer.setCallback(new CustomerCglibMethodInterceptor());
// 创建代理对象
Service service = (Service)enhancer.create();
service.process();
}
上面代码对所有的方法都执行同样的增强,如果我想对不同的方法实现不同的增强,例如:get开头的方法记录执行时间,set开头的方法记录详细日志。
定义一个ConditionCallback接口,它继承MethodInterceptor并提供一个方法匹配的功能。
public interface ConditionCallback extends MethodInterceptor {
boolean isMatch(Method method);
}
定义两个MethodInterceptor实现类,提供两种不同的增强。
public class ConditionGetMethodInterceptor implements ConditionCallback{
@Override
public boolean isMatch(Method method) {
// 处理get方法
if(method.getName().startsWith("get")){
return true;
}
return false;
}
// get方法记录执行时间
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
long start = System.currentTimeMillis();
Object invokeSuper = methodProxy.invokeSuper(o, objects);
System.out.println(String.format("方法%s执行时间:%d 毫秒",method.getName(),(System.currentTimeMillis() - start)));
return invokeSuper;
}
}
public class ConditionSetMethodInterceptor implements ConditionCallback{
@Override
public boolean isMatch(Method method) {
if(method.getName().startsWith("set")){
return true;
}
return false;
}
// set方法进行日志记录
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
String methodName = method.getName();
System.out.println("method = " + methodName + " ,args= " + Arrays.deepToString(objects));
System.out.println("method = " + methodName + " ,before doing... ");
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("method = " + methodName + " ,after doing... ");
return invoke;
}
}
定义一个CallbackFilter,在执行不同的方法时调用不同的MethodInterceptor进行增强。
public class ConditionFilter implements CallbackFilter {
private final Callback[] callbacks;
public ConditionFilter(Callback[] callbacks){
this.callbacks = callbacks;
}
@Override
public int accept(Method method) {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof ConditionCallback){
if(((ConditionCallback) callbacks[i]).isMatch(method)){
return i;
}
}else {
throw new IllegalStateException("No callback available for method " + method.getName());
}
}
return 0;
}
}
需要注意的是,如果设置了callbacks,需要与callbackFilter配套使用,不然会报错。
public static void main(String[] args) {
// 实现多种增强效果
Callback[] callbacks = new Callback[]{new ConditionGetMethodInterceptor(),new ConditionSetMethodInterceptor()};
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(BasicService.class);
enhancer.setCallbacks(callbacks);
//和callbacks配套使用,不然会报错
enhancer.setCallbackFilter(new ConditionFilter(callbacks));
BasicService service = (BasicService)enhancer.create();
service.getData();
service.setSystemCache("zhangli",new Object());
}
通过上面的学习,我们对代理模式有了基本的了解, 也方便我们阅读Spring中关于动态代理部分的源码。
我们先来看一段代码。
下面的A对象会实例化几次?两次
@Component
public class SpringProxy {
@Bean
public A a(){
System.out.println("init A");
return new A();
}
@Bean
public B b(){
a();
System.out.println("init B");
return new B();
}
}
看控制台的打印:、
init A
init A
init B
可以看到a()方法被调用了两次,即A对象被创建了两次,按照我们的理解,既然我们把在a()方法上加了@Bean,那它就会生成对应的beanDefinition,相对于是Spring中的Bean了,默认情况下应该是单例的,那为什么a()方法被调用了两次(A对象实例化两次)。
接下来,我们把类上的@Component注解由改成@Configuration注解,现在,发现a()方法只被调用了一次。这就符合我们的预期了,为什么会这样?那Spring中是如何实现的呢?
记得上一篇文章我们已经阅读完解析@Component和@Configuration及@Bean注解的源码,好像也没有看到相关处理,除了会将全配置类的BD的属性CONFIGURATION_CLASS_ATTRIBUTE的值设置为CONFIGURATION_CLASS_FULL,属性,简洁配置类的BD的属性CONFIGURATION_CLASS_ATTRIBUTE的设置为CONFIGURATION_CLASS_LITE。(解析配置类源码分析)这其实也是Spring中代理的应用点之一,我们在上篇文章最后也提示了ConfigurationClassPostProcessor类的其中一个功能就是生成CGLIB代理对象,具体逻辑在BeanFactoryPostProcessor的接口方法postProcessBeanFactory()中实现的。话不多说,我们直接看源码吧!
源码分析
Spring在ConfigurationClassPostProcessor类的postProcessBeanFactory()方法中实现动态代理的,该方法是BeanFactoryPostProcessor的接口方法。
这个方法中完成配置类进行增强,生成对应的代理对象。同时添加一个ImportAwareBeanPostProcessor类型的后置处理器到容器中。
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
//生成代理对象
// 代码块一:对配置类进行增强
enhanceConfigurationClasses(beanFactory);
///添加一个ImportAwareBeanPostProcessor类型的后置处理器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
就是将容器中的所有符合要求的配置类找到(是否全配置类),放入候选集合,然后遍历候选集合,完成对应方法的增强,同时将代理对象的class设置为BD的beanClass属性的值。
/**后置处理从一个BeanFactory查找到的配置类的BeanDefinitions;
* 然后通过{@link ConfigurationClassEnhancer}增强任何候选对象。
* 候选状态由BeanDefinition属性元数据决定。
**/
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
StartupStep enhanceConfigClasses = this.applicationStartup.start("spring.context.config-classes.enhance");
// 存放候选的beanDefinition(全配置类才会添加到这个集合)
Map configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
// 候选条件属性
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
MethodMetadata methodMetadata = null;
if (beanDef instanceof AnnotatedBeanDefinition) {
// @Bean标记的方法生成的beanDefinition设置了这个值
methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
}
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
// Configuration class (full or lite) or a configuration-derived @Bean method
// -> resolve bean class at this point...
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
if (!abd.hasBeanClass()) {
try {
// 确保beanClass被解析
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
//找到所有符合标准的全配置类
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
//将全配置类放入map
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
//
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
enhanceConfigClasses.end();
return;
}
if (IN_NATIVE_IMAGE) {
throw new BeanDefinitionStoreException("@Configuration classes need to be marked as proxyBeanMethods=false. Found: " + configBeanDefs.keySet());
}
//创建配置类代理增强器
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
//循环map,生成代理对象
for (Map.Entry entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
//代理的标识,是否被代理
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// Set enhanced subclass of the user-specified bean class
//原始对象
Class> configClass = beanDef.getBeanClass();
//CGLIB代理是基于父类实现的(继承)
//代理对象
// 代码二:使用CGLIB代理对配置类进行增强
Class> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
if (logger.isTraceEnabled()) {
logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
}
//将生成的代理对象放入BD
beanDef.setBeanClass(enhancedClass);
}
}
enhanceConfigClasses.tag("classCount", () -> String.valueOf(configBeanDefs.keySet().size())).end();
}
public Class> enhance(Class> configClass, @Nullable ClassLoader classLoader) {
//判断是否被代理过
//spring生成的代理类实现类EnhancedConfiguration接口
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Ignoring request to enhance %s as it has " +
"already been enhanced. This usually indicates that more than one " +
"ConfigurationClassPostProcessor has been registered (e.g. via " +
"). This is harmless, but you may " +
"want check your configuration and remove one CCPP if possible",
configClass.getName()));
}
return configClass;
}
// 代码三:创建代理对象对应的class
Class> enhancedClass = createClass(newEnhancer(configClass, classLoader));
if (logger.isTraceEnabled()) {
logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
configClass.getName(), enhancedClass.getName()));
}
return enhancedClass;
}
private Class> createClass(Enhancer enhancer) {
Class> subclass = enhancer.createClass();
// Registering callbacks statically (as opposed to thread-local)
// is critical for usage in an OSGi environment (SPR-5932)...
// 代码四:注册回调函数
Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
return subclass;
}
根据不同方法调用不同的Callback完成方法的增强。
// 回调函数都是无状态的
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {
……
//Class类型不属于Object.class,不是setFactoryBean()且方法上有@Bean注解
@Override
public boolean isMatch(Method candidateMethod) {
return (candidateMethod.getDeclaringClass() != Object.class &&
!BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
}
……
}
private static class BeanFactoryAwareMethodInterceptor implements MethodInterceptor, ConditionalCallback {
……
// setBeanFactory()方法才会执行这部分的增强
@Override
public boolean isMatch(Method candidateMethod) {
return isSetBeanFactory(candidateMethod);
}
// 方法名为setBeanFactory()且方法类型为BeanFactoryAware,才会执行这部分的增强
public static boolean isSetBeanFactory(Method candidateMethod) {
return (candidateMethod.getName().equals("setBeanFactory") &&
candidateMethod.getParameterCount() == 1 &&
BeanFactory.class == candidateMethod.getParameterTypes()[0] &&
BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass()));
}
……
}
public static void registerStaticCallbacks(Class generatedClass, Callback[] callbacks) {
setCallbacksHelper(generatedClass, callbacks, "CGLIB$SET_STATIC_CALLBACKS");
}
private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName) {
try {
// Callback中methodName对应的方法
Method setter = getCallbacksSetter(type, methodName);
setter.invoke((Object)null, callbacks);
} catch (NoSuchMethodException var4) {
throw new IllegalArgumentException(type + " is not an enhanced class");
} catch (IllegalAccessException var5) {
throw new CodeGenerationException(var5);
} catch (InvocationTargetException var6) {
throw new CodeGenerationException(var6);
}
}
private static Method getCallbacksSetter(Class type, String methodName) throws NoSuchMethodException {
return type.getDeclaredMethod(methodName, Callback[].class);
}
//代码四:创建CGLIB代理增强器实例
/**
* Creates a new CGLIB {@link Enhancer} instance.
*/
private Enhancer newEnhancer(Class> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);
enhancer.setInterfaces(new Class>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
//设置用于增强CallbackFilter
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
这里CallbackFilter的作用我们在代码演示里面大概知道其用途了。
private static class ConditionalCallbackFilter implements CallbackFilter {
private final Callback[] callbacks;
private final Class>[] callbackTypes;
// callbacks数组赋值
public ConditionalCallbackFilter(Callback[] callbacks) {
this.callbacks = callbacks;
this.callbackTypes = new Class>[callbacks.length];
for (int i = 0; i < callbacks.length; i++) {
this.callbackTypes[i] = callbacks[i].getClass();
}
}
// 根据不同的方法匹配不同的callback
@Override
public int accept(Method method) {
for (int i = 0; i < this.callbacks.length; i++) {
Callback callback = this.callbacks[i];
if (!(callback instanceof ConditionalCallback) || ((ConditionalCallback) callback).isMatch(method)) {
return i;
}
}
throw new IllegalStateException("No callback available for method " + method.getName());
}
public Class>[] getCallbackTypes() {
return this.callbackTypes;
}
}
通过上面对CALLBACKS数组简单了解,其中包含一个BeanMethodInterceptor实例,也了解了系统中注入的两个MethodInterceptor的isMatch()方法,使用BeanMethodInterceptor进行的情况居多,它会对大部分@Bean方法进行增强。
方法大致总结为:
1)根据方法名推断beanName。默认值为方法名称,如果有配置name属性,只要一个值时为这个唯一值,有多个值时,取下标为0的值 。
2)获取Bean方法对应的代理模式,默认为NO。
3)检查所请求的bean是否是FactoryBean。如果是,创建一个子类完成代理。如果FactoryBean或其接口方法getObject()有一个被final修饰,如果是,存在如下两种情况。
a.方法返回值类型为接口,通过JDK动态代理完成方法增强。
b.如果返回值类型不是接口,无法完成代理,直接直接返回FactoryBean
否则通过CGLIB代理完成方法增强。
4)判断当前创建Bean的方法与实际调用的方法一致。比较线程本地变量存储的factoryMethod与当前方法是否一致。(方法名和参数列表一致)
a.如果一致,通过CGLIB代理完成方法增强,会执行父类方法,即@Bean方法里面实例化对象的方法。
b.如果不一致,根据当前调用方法对应的beanName和方法参数通过getBean获取相关实例beanInstance,设置该实例与factoryMethod对应的bean的依赖关系。返回这个实例对象。
private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {
@Override
@Nullable
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
// 获取方法对应的beanName
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// Determine whether this bean is a scoped-proxy
if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
beanName = scopedBeanName;
}
}
// 检查所请求的bean是否是FactoryBean。如果是,创建一个子类
if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
factoryContainsBean(beanFactory, beanName)) {
Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
// Scoped proxy factory beans are a special case and should not be further proxied
//有作用域的代理工厂bean是一种特殊情况,不应该被进一步代理
}
else {
// It is a candidate FactoryBean - go ahead with enhancement
// 代码六:对候选FactoryBean进行增强
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
}
}
//代码块九:当前创建Bean的方法与实际调用的方法一致
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
// The factory is calling the bean method in order to instantiate and register the bean
// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
// create the bean instance.
if (logger.isInfoEnabled() &&
BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
"result in a failure to process annotations such as @Autowired, " +
"@Resource and @PostConstruct within the method's declaring " +
"@Configuration class. Add the 'static' modifier to this method to avoid " +
"these container lifecycle issues; see @Bean javadoc for complete details.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
}
//调用父类方法创建bean
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
//当前创建bean的方法与实际调用的方法不一致
/**例如:
* f(){
* e();
* }
* 在执行f()方法中调用了e()方法;
* 当前执行的是f()方法,在执行到e()时,实际调用了e(),就会执行resolveBeanReference
* 类似于beanMethod就是当前执行方法栈的栈顶方法,f()是这个方法栈
*/
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
这个方法大概总结为:
1) FactoryBean类及其getObject()方法是否被final修饰,如果这两个其中一个被final修饰。
a.如果是方法的返回值是接口类型,则通过JDK动态代理完成方法增强
b.不是接口类型,无法进行代理,直接返回FactoryBean。
2)如果不被final修饰,通过CGLIB代理实现方法增强。
private Object enhanceFactoryBean(final Object factoryBean, Class> exposedType,
final ConfigurableBeanFactory beanFactory, final String beanName) {
try {
Class> clazz = factoryBean.getClass();
// 类是否被final修饰
boolean finalClass = Modifier.isFinal(clazz.getModifiers());
// factoryBean的getObject()方法是否被final修饰
boolean finalMethod = Modifier.isFinal(clazz.getMethod("getObject").getModifiers());
if (finalClass || finalMethod) {
// 如果是接口
if (exposedType.isInterface()) {
if (logger.isTraceEnabled()) {
logger.trace("Creating interface proxy for FactoryBean '" + beanName + "' of type [" +
clazz.getName() + "] for use within another @Bean method because its " +
(finalClass ? "implementation class" : "getObject() method") +
" is final: Otherwise a getObject() call would not be routed to the factory.");
}
// 代码七:通过FactoryBean创建接口类型的代理
return createInterfaceProxyForFactoryBean(factoryBean, exposedType, beanFactory, beanName);
}
else {
// 打印日志,final类型的类或final无法进行代理
if (logger.isDebugEnabled()) {
logger.debug("Unable to proxy FactoryBean '" + beanName + "' of type [" +
clazz.getName() + "] for use within another @Bean method because its " +
(finalClass ? "implementation class" : "getObject() method") +
" is final: A getObject() call will NOT be routed to the factory. " +
"Consider declaring the return type as a FactoryBean interface.");
}
return factoryBean;
}
}
}
catch (NoSuchMethodException ex) {
// No getObject() method -> shouldn't happen, but as long as nobody is trying to call it...
}
// 代码八:通过FactoryBean创建CGLIB类型的代理
return createCglibProxyForFactoryBean(factoryBean, beanFactory, beanName);
}
// 通过FactoryBean创建接口类型的代理
private Object createInterfaceProxyForFactoryBean(final Object factoryBean, Class> interfaceType,
final ConfigurableBeanFactory beanFactory, final String beanName) {
//通过JDK动态代理实现对目标接口的增强
return Proxy.newProxyInstance(
factoryBean.getClass().getClassLoader(), new Class>[] {interfaceType},
(proxy, method, args) -> {
if (method.getName().equals("getObject") && args == null) {
return beanFactory.getBean(beanName);
}
return ReflectionUtils.invokeMethod(method, factoryBean, args);
});
}
private Object createCglibProxyForFactoryBean(final Object factoryBean,
final ConfigurableBeanFactory beanFactory, final String beanName) {
// 创建CGLIB增强器
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(factoryBean.getClass());
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setCallbackType(MethodInterceptor.class);
// Ideally create enhanced FactoryBean proxy without constructor side effects,
// analogous to AOP proxy creation in ObjenesisCglibAopProxy...
Class> fbClass = enhancer.createClass();
Object fbProxy = null;
// SpringObjenesis
// spring特定变体,提供基于{@code Class}键而不是类名的缓存;
// 就是通过Class可以获取对应的缓存实例
// 从objenesis缓存获取对象
if (objenesis.isWorthTrying()) {
try {
fbProxy = objenesis.newInstance(fbClass, enhancer.getUseCache());
}
catch (ObjenesisException ex) {
logger.debug("Unable to instantiate enhanced FactoryBean using Objenesis, " +
"falling back to regular construction", ex);
}
}
if (fbProxy == null) {
try {
// 通过无参构造器创建对象
fbProxy = ReflectionUtils.accessibleConstructor(fbClass).newInstance();
}
catch (Throwable ex) {
throw new IllegalStateException("Unable to instantiate enhanced FactoryBean using Objenesis, " +
"and regular FactoryBean instantiation via default constructor fails as well", ex);
}
}
((Factory) fbProxy).setCallback(0, (MethodInterceptor) (obj, method, args, proxy) -> {
if (method.getName().equals("getObject") && args.length == 0) {
return beanFactory.getBean(beanName);
}
return proxy.invoke(factoryBean, args);
});
return fbProxy;
}
我们需要明白什么时候会执行@Bean标记的方法?
在实例对象的时候,@Bean标记的方法是被作为FactoryMethod创建实例的一种。最终都是会调用SimpleInstantiationStrategy的实例化方法instantiate()进行对象的实例化,
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
……
if (mbd.getFactoryMethodName() != null) {
// 实例化对象的工厂方法也存在重载的情况,推断工厂方法的逻辑与推断构造器的逻辑类似
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
……
}
而SimpleInstantiationStrategy类维护了一个线程本地变量currentlyInvokedFactoryMethod,用来存储当前线程执行的FactoryMethod,实例化方法instantiate()中会给这个变量设置值。
public class SimpleInstantiationStrategy implements InstantiationStrategy {
//当前线程执行的FactoryMethod
private static final ThreadLocal currentlyInvokedFactoryMethod = new ThreadLocal<>();
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Object factoryBean, final Method factoryMethod, Object... args) {
// 设置线程本地变量值
currentlyInvokedFactoryMethod.set(factoryMethod);
Object result = factoryMethod.invoke(factoryBean, args);
if (result == null) {
result = new NullBean();
}
return result;
}
}
比较当前调用方法与线程本地变量存储的factoryMethod的方法名称及形参列表(形参个数及形参类型都一致) 是否一致。
// 判断method与当前的FactoryMethod是否相同
private boolean isCurrentlyInvokedFactoryMethod(Method method) {
// 当前创建bean对应的方法(@Bean标记的方法名会被作为FactoryMethod保存在缓存中)
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
// 方法名和参数列表(个数和参数类型)相同
return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}
如果一致,使用CGLIB代理,就会执行父类方法。
当前创建bean的方法与实际调用的方法不一致时,会进入这个方法,我们看到,这里获取beanName对应的实例是通过getBean(),而不是调用实例化方法instantiate(),所以不会多次实例化。
这个方法大概总结为:
1)判断当前对象beanName是否正在创建,如果是,临时设置创建中的状态为 false,以避免异常。
2)获取方法参数数组,如果方法参数数组中有一个值为null,舍弃参数,因为初始化或获取对应的实例时,不运行构造参数模棱两可。
3)如果是参数不满足要求,获取(或创建,看容器中是否存在)无参实例。满足要求则获取(或创建,看容器中是否存在)有参实例。
4)如果获取的实例beanInstance不为null,但方法返回值类型与实例类型不匹配,抛出异常(IllegalStateException)。
5)获取线程本地变量存储的factoryMethod,设置当前实例beanInstance对应的beanName与其的依赖关系。返回beanInstance。(相对于beanInstance是factoryMethod对应的bean的一个属性。)
6)设置创建中的状态的值。
private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
ConfigurableBeanFactory beanFactory, String beanName) {
// The user (i.e. not the factory) is requesting this bean through a call to
// the bean method, direct or indirect. The bean may have already been marked
// as 'in creation' in certain autowiring scenarios; if so, temporarily set
// the in-creation status to false in order to avoid an exception.
// 是否正在创建,false
boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
try {
if (alreadyInCreation) {
beanFactory.setCurrentlyInCreation(beanName, false);
}
boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
// 参数不为空且是单例对象
if (useArgs && beanFactory.isSingleton(beanName)) {
// Stubbed null arguments just for reference purposes,
// expecting them to be autowired for regular singleton references?
// A safe assumption since @Bean singleton arguments cannot be optional...
for (Object arg : beanMethodArgs) {
if (arg == null) {
useArgs = false;
break;
}
}
}
//不是直接调用父类方法(new),而是通过beanFactory.getBean(beanName)
// 要不要传参,如果beanMethodArgs包含有null值,调用无参的方法获取bean
// 为什么不会实例化多次的原因,先去从容器中获取
Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
beanFactory.getBean(beanName));
if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
// Detect package-protected NullBean instance through equals(null) check
if (beanInstance.equals(null)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("@Bean method %s.%s called as bean reference " +
"for type [%s] returned null bean; resolving to null value.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
beanMethod.getReturnType().getName()));
}
beanInstance = null;
}
else {
String msg = String.format("@Bean method %s.%s called as bean reference " +
"for type [%s] but overridden by non-compatible bean instance of type [%s].",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
try {
BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore - simply no detailed message then.
}
throw new IllegalStateException(msg);
}
}
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
if (currentlyInvoked != null) {
// 默认为方法名,如果自定义了name,使用自定义的name,如果自定义了多个name,取下标为0的那个作为name
String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
// 维护依赖关系集合,beanName需要被添加到哪些bean(dependentBeanMap),outerBeanName需要哪些依赖(dependenciesForBean)
beanFactory.registerDependentBean(beanName, outerBeanName);
}
return beanInstance;
}
finally {
// false
if (alreadyInCreation) {
// 设置为正在创建
beanFactory.setCurrentlyInCreation(beanName, true);
}
}
}
如果方法名称为setBeanFactory()且返回值类型为BeanFactoryAware.class,直接调用父类的setBeanFactory()方法,不进行任何增强。
private static class BeanFactoryAwareMethodInterceptor implements MethodInterceptor, ConditionalCallback {
@Override
@Nullable
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 根据class类型和name查找field
Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
Assert.state(field != null, "Unable to find generated BeanFactory field");
field.set(obj, args[0]);
// Does the actual (non-CGLIB) superclass implement BeanFactoryAware?
// If so, call its setBeanFactory() method. If not, just exit.
if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
//调用BeanFactoryAware.setBeanFactory()
return proxy.invokeSuper(obj, args);
}
return null;
}
}
看完源码,我们对如下代码进行分析。
@Configuration
public class SpringProxy {
@Bean
public A a(){
System.out.println("init A");
return new A();
}
@Bean
public B b(){
a();
System.out.println("init B");
return new B();
}
}
1)A对象实例化时,通过工厂方法实例化 A对象,把当前线程本地变量currentlyInvokedFactoryMethod赋值为a(),进入a()方法,判断当前调用方法(a())是否与线程本地变量存储的factoryMethod一致,一致,执行CGLIB代理,就会调用父类方法进行实例化。(new A())。
2)B对象实例化时,通过工厂方法实例化 B对象,把当前线程本地变量currentlyInvokedFactoryMethod赋值为b(),进入b()方法,判断当前调用方法(b())是否与线程本地变量存储的factoryMethod一致,一致,执行CGLIB代理,就会调用父类方法进行实例化。(a())。
3)B对象实例化调用父类方法时,会执行a()方法,判断当前调用方法(a())是否与线程本地变量存储的factoryMethod(b())一致,不一致,获取方法名和方法参数,通过getBean()获取方法对应的实例对象beanInstance,并把该实例作为当前线程本地变量存储的factoryMethod(b())对应的bean的一个依赖,并进行维护依赖关系相关集合。返回获取的beanInstance。
4)a()返回后,继续执行(b())父类的方法(new B()),完成B对象的实例化。
我们知道java类实例化的基本流程是先将.java文件编译成.class文件,然后通过类加载器加载class文件到jvm中,jvm将class解析成字节码(byte)。而动态代理则是直接生成对应的字节码(byte),在需要创建大量类的系统中,使用动态代理可以防止类爆炸。
通过前面的源码阅读,@Configuration注解标识的类会使用代理,可以保证生成的对象是单例的,我们在开发中可以好好利用这个特性。