1.写在前面
上一篇博客大概讲了一下Spring
的扫描机制,但是调用ConfigurationClassPostProcessor
类中的postProcessBeanDefinitionRegistry
方法,由于这个方法比较复杂,笔者只讲了下什么类会被解析成配置类,还有讲了一下Spring
是如何调用的doScan
的方法的。解析成配置类最终的表现的形式就是给BeanDefinition
中的Attribute
的属性中的org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass
的值设置成full
或者是lite
,那这两个有什么区别呢?就是我们这篇博客要解决的问题。
2.Lite与Full
上一篇博客中我们写到,只有是加了@Configuration的
注解,同时@Configuration
注解中proxyBeanMethods
的值为true
,这个时候属性的值为full
,如果是proxyBeanMethods
的值为false
,那么这个时候属性的值就为lite
。那笔者可以写出如下的代码,具体的代码如下:
package com.ys.configurationTest;
public class A {
}
- 1
- 2
- 3
- 4
package com.ys.configurationTest;
public class B {
}
- 1
- 2
- 3
- 4
package com.ys.configurationTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration()
public class AppConfig {
@Bean
public A a() {
System.out.println("a init");
b();
return new A();
}
@Bean
public B b() {
System.out.println("b init");
return new B();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
package com.ys.configurationTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
运行的结果如下:
上面的情况是full
的情况,可以发现我们b init
这个就打印了一次,但是如果我们将AppConfig
这个类改成如下的代码:
package com.ys.configurationTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class AppConfig {
@Bean
public A a() {
System.out.println("a init");
b();
return new A();
}
@Bean
public B b() {
System.out.println("b init");
return new B();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
这个时候运行的结果如下:
你会发现b init
打印了两次,证明这个对象不是单例,同时也是lite
的情况。那么为什么有这种区别呢?我们可以看下两种打印的AppConfig
的类型。下面是full的运行的结果。具体如下:
可以发现我们的AppConfig
类成了一个Cglib的代理类。我们再看下lite
的运行的结果,结果如下:
是原始的类型,所以可以确定的就是如果是full
类型的,AppConfig
就是Cglib
的代理的代理类。同时我们也在官网找到了对应的解释,具体的如下:
大概的区别:
- lite @Bean方法不能声明Bean之间的依赖关系,相反,它们对包含它们的组件的内部状态进行操作,并可选地对它们可能声明的参数进行操作。因此,这样的@Bean方法不应该调用其他的@Bean方法。
- full 确保跨方法引用因此被重定向到容器的生命周期管理。也就是保证是单例的。
那么Spring是如何实现的呢?要搞懂这个问题,我们需要了解一下Cglib的知识。
3.Cglib的简单的使用
3.1Cglib是什么?
Cglib是一个强大的、高效的代码生成包,它广泛被许多AOP框架使用,为他们提供方法的拦截。下图是对应的Cglib与一些框架和语言的关系:
对此图总结一下:
- 最底层的是字节码ByteCode,字节码是Java为了保证“一次编译、到处运行”而产生的一种虚拟指令格式,例如iload_0、iconst_1、if_icmpne、dup等
- 位于字节码之上的是ASM,这是一种直接操作字节码的框架,应用ASM需要对Java字节码、Class结构比较熟悉
- 位于ASM之上的是
CGLIB
、Groovy
、BeanShell
,后两种并不是Java体系中的内容而是脚本语言,它们通过ASM框架生成字节码变相执行Java代码,这说明在JVM中执行程序并不一定非要写Java代码----只要你能生成Java字节码,JVM并不关心字节码的来源,当然通过Java代码生成的JVM字节码是通过编译器直接生成的,算是最“正统”的JVM字节码 - 位于CGLIB、Groovy、BeanShell之上的就是Hibernate、Spring AOP这些框架了,这一层大家都比较熟悉
- 最上层的是Applications,即具体应用,一般都是一个Web项目或者本地跑一个程序
3.2使用Cglib代码对类做代理
下面演示一下Cglib代码示例----对类做代理。首先定义一个Dao类,里面有一个select()方法和一个update()方法:
package com.ys.configurationTest.cglib;
public class Dao {
public void select() {
System.out.println("Dao.select");
}
public void update() {
System.out.println("Dao.update");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
创建一个Dao
代理类,实现MethodInterceptor
接口,目标是在update()
方法与select()
方法调用前后输出两句话:
package com.ys.configurationTest.cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class DaoProxy implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
System.out.println("Before Method Invoke");
proxy.invokeSuper(object, objects);
System.out.println("After Method Invoke");
return object;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
intercept
方法的参数名并不是原生的参数名,我做了自己的调整,几个参数的含义为:
Object
表示要进行增强的对象Method
表示拦截的方法Object[]
数组表示参数列表,基本数据类型需要传入其包装类型,如int–>Integer、long-Long、double–>DoubleMethodProxy
表示对方法的代理,invokeSuper
方法表示对被代理对象方法的调用
写一个测试类
package com.ys.configurationTest.cglib;
import net.sf.cglib.proxy.Enhancer;
import org.junit.jupiter.api.Test;
public class CglibTest {
@Test
public void testCglib() {
DaoProxy daoProxy = new DaoProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Dao.class);
enhancer.setCallback(daoProxy);
Dao dao = (Dao)enhancer.create();
dao.update();
dao.select();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
运行的结果如下:
3.3使用Cglib定义不同的拦截策略
再扩展一点点,比方说在AOP中我们经常碰到的一种复杂场景是:我们想对类A的B方法使用一种拦截策略、类A的C方法使用另外一种拦截策略。
在本例中,即我们想对select()方法与update()方法使用不同的拦截策略,那么我们先定义一个新的Proxy:
package com.ys.configurationTest.cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class DaoAnotherProxy implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
System.out.println("StartTime=[" + System.currentTimeMillis() + "]");
proxy.invokeSuper(object, objects);
System.out.println("EndTime=[" + System.currentTimeMillis() + "]");
return object;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
方法调用前后输出一下开始时间与结束时间。为了实现我们的需求,实现一下CallbackFilter
:
package com.ys.configurationTest.cglib;
import net.sf.cglib.proxy.CallbackFilter;
import java.lang.reflect.Method;
public class DaoFilter implements CallbackFilter {
@Override
public int accept(Method method) {
if ("select".equals(method.getName())) {
return 0;
}
return 1;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
返回的数值表示顺序,结合下面的代码解释,测试代码要修改一下:
package com.ys.configurationTest.cglib;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;
import org.junit.jupiter.api.Test;
public class CglibTest {
@Test
public void testCglib() {
DaoProxy daoProxy = new DaoProxy();
DaoAnotherProxy daoAnotherProxy = new DaoAnotherProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Dao.class);
enhancer.setCallbacks(new Callback[]{daoProxy, daoAnotherProxy, NoOp.INSTANCE});
enhancer.setCallbackFilter(new DaoFilter());
Dao dao = (Dao)enhancer.create();
dao.update();
dao.select();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
意思是CallbackFilter
的accept
方法返回的数值表示的是顺序,顺序和setCallbacks
里面Proxy
的顺序是一致的。再解释清楚一点,Callback
数组中有三个callback
,那么:
- 方法名为"select"的方法返回的顺序为0,即使用
Callback
数组中的0位callback
,即DaoProxy
- 方法名不为"select"的方法返回的顺序为1,即使用
Callback
数组中的1位callback
,即DaoAnotherProxy
因此,方法的执行结果为:
符合我们的预期,因为update()
方法不是方法名为"select"的方法,因此返回1,返回1使用DaoAnotherProxy
,即打印时间;select()
方法是方法名为"select"的方法,因此返回0,返回0使用DaoProxy
,即方法调用前后输出两句话。
这里要额外提一下,Callback
数组中我特意定义了一个NoOp.INSTANCE
,这表示一个空Callback
,即如果不想对某个方法进行拦截,可以在DaoFilter
中返回2,具体效果可以自己尝试一下。
3.4构造函数不拦截方法
如果update()
方法与select()
方法在构造函数中被调用,那么也是会对这两个方法进行相应的拦截的,现在我想要的是构造函数中调用的方法不会被拦截,那么应该如何做?先改一下Dao
代码,加一个构造方法Dao()
,调用一下update()
方法:
package com.ys.configurationTest.cglib;
public class Dao {
public Dao() {
update();
}
public void select() {
System.out.println("Dao.select");
}
public void update() {
System.out.println("Dao.update");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
如果想要在构造函数中调用update()
方法时,不拦截的话,Enhancer
中有一个setInterceptDuringConstruction(boolean interceptDuringConstruction)
方法设置为false
即可,默认为true
,即构造函数中调用方法也是会拦截的。那么测试方法这么写:
package com.ys.configurationTest.cglib;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;
import org.junit.jupiter.api.Test;
public class CglibTest {
@Test
public void testCglib() {
DaoProxy daoProxy = new DaoProxy();
DaoAnotherProxy daoAnotherProxy = new DaoAnotherProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Dao.class);
enhancer.setCallbacks(new Callback[]{daoProxy, daoAnotherProxy, NoOp.INSTANCE});
enhancer.setCallbackFilter(new DaoFilter());
enhancer.setInterceptDuringConstruction(false);
Dao dao = (Dao) enhancer.create();
dao.update();
dao.select();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
运行结果为:
看到第一次update()
方法的调用,即Dao
类构造方法中的调用没有拦截,符合预期。
4.Spring中怎么对full的配置类进行代理的
上次我们的博客主要讲了ConfigurationClassPostProcessor
类中的postProcessBeanDefinitionRegistry
类的方法,这个方法主要负责扫描然后处理这个类上面的一些注解,但是这个方法比较复杂,我们只介绍了一部分。而进行代理的方法就是调用postProcessBeanFactory
方法,具体代码如下:
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//获取对应的hashcode,主要用来看看有没有执行过
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
//如果没有执行过,就添加到factoriesPostProcessed
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);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
上面的方法enhanceConfigurationClasses(beanFactory);
是进行生成对应的代理类。具体的代码如下:
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
//创建一个Map用来存配置的BeanDefinition
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
//遍历所有的BeanDefinition的名字
for (String beanName : beanFactory.getBeanDefinitionNames()) {
//根据BeanDefinition的名字获取对应的BeanDefinition
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
//获取之前设置的属性,是full还lite,还是是null
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
MethodMetadata methodMetadata = null;
//只有是配置类才会进这个判断
if (beanDef instanceof AnnotatedBeanDefinition) {
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;
//判断是否有对应的beanClass
if (!abd.hasBeanClass()) {
try {
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
//判断这个设置是不是full
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);
}
}
//如果没有指定配置类,和配置类是lite的属性,就直接返回,不进行下面的代理了
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
//遍历刚才的Map
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
//获取对应BeanDefinition
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();
//创建代理类
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()));
}
//将原来的BeanDefinition的BeanClass的属性改成代理类的
beanDef.setBeanClass(enhancedClass);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
上面的代码就是进行一系列的判断,判断解析的类的属性是不是Full,如果是的话,就进行对应的代理,如果不是,就直接return,不进行对应的代理。然后代理类生成的方法主要是enhancer.enhance(configClass, this.beanClassLoader);
方法,具体的代码如下:
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
//有两个Class类型的类象,一个是调用isAssignableFrom方法的类对象(后称对象a),
//以及方法中作为参数的这个类对象(称之为对象b),这两个对象如果满足以下条件则返回true,否则返回false:
//a对象所对应类信息是b对象所对应的类信息的父类或者是父接口,简单理解即a是b的父类或接口
//a对象所对应类信息与b对象所对应的类信息相同,简单理解即a和b为同一个类或同一个接口
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 " +
"<context:annotation-config>). This is harmless, but you may " +
"want check your configuration and remove one CCPP if possible",
configClass.getName()));
}
return configClass;
}
//创建对应的代理类
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
上面代码走来先判断这个类是否解析过了,如果没有再生成代理,主要生成代理的方法就是 createClass(newEnhancer(configClass, classLoader));
,首先我们先看下newEnhancer(configClass, classLoader)
代码,具体的代码如下:
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(configSuperClass);
//设置接口
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
//设置名字生成策略 加上BySpringCGLIB
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
//设置拦截的策略
enhancer.setCallbackFilter(CALLBACK_FILTER);
//设置拦截的类型
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
上面设置拦截的策略,我们需要看它指定的数组,同时还要看accept
的方法。具体的代码如下:
private static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
- 1
- 2
- 3
- 4
- 5
@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());
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
我们分别看下BeanMethodInterceptor
的指定的isMatch(method)
的代码,具体如下:
@Override
public boolean isMatch(Method candidateMethod) {
//判断不是Object类,同时不是实现BeanFactoryAware接口的是setBeanFactory方法,同时也是加了@Bean的注解的
return (candidateMethod.getDeclaringClass() != Object.class &&
!BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
然后我们再看下BeanFactoryAwareMethodInterceptor
的指定的isMatch(method)
的代码,具体的如下:
@Override
public boolean isMatch(Method candidateMethod) {
//判断这个方法是不是实现BeanFactoryAware接口的setBeanFactory方法
return isSetBeanFactory(candidateMethod);
}
public static boolean isSetBeanFactory(Method candidateMethod) {
return (candidateMethod.getName().equals("setBeanFactory") &&
candidateMethod.getParameterCount() == 1 &&
BeanFactory.class == candidateMethod.getParameterTypes()[0] &&
BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass()));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
所以看了上面的拦截的规则,我们大概知道了拦截的规则,就是如果是加了@Bean
注解的方法,同时不是实现BeanFactoryAware
接口的setBeanFactory
方法,会调用BeanMethodInterceptor
中的intercept
的方法。如果是实现BeanFactoryAware
接口的setBeanFactory
方法,就会调用BeanFactoryAwareMethodInterceptor
中的intercept
的方法。
4.1BeanMethodInterceptor
我们先看BeanMethodInterceptor
中的intercept
的方法,具体的代码如下:
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
//获取对应的BeanFactory
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
//获取对应的BeanName
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// Determine whether this bean is a scoped-proxy
//判断这个bean是不是scoped-proxy
if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
beanName = scopedBeanName;
}
}
// To handle the case of an inter-bean method reference, we must explicitly check the
// container for already cached instances.
// First, check to see if the requested bean is a FactoryBean. If so, create a subclass
// proxy that intercepts calls to getObject() and returns any cached bean instance.
// This ensures that the semantics of calling a FactoryBean from within @Bean methods
// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
//首先,检查所请求的bean是否为FactoryBean。
//如果是这样,则创建一个子类代理,以拦截对getObject()的调用并返回所有缓存的Bean实例。
//这样可确保从@Bean方法中调用FactoryBean的语义
//与在XML中引用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
}
else {
// It is a candidate FactoryBean - go ahead with enhancement
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
}
}
//如果不是就是正常的方法,并不是处理FactoryBean的 判断是不是调用当前的工厂的方法
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()));
}
//是的话就直接调用父类的方法,也就是原始的创建的方法
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
//不是的话,就会调用如下的方法
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
在别的方法中调用这个创建FactoryBean
的方法。首先,检查所请求的bean
是否为FactoryBean
。如果是这样,则创建一个子类代理,以拦截对getObject()的调用并返回所有缓存的Bean实例。判断是不是 ScopedProxyFactoryBean
,如果是,就不进行下一步的处理,如果不是调用enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
方法,具体的代码如下:
private Object enhanceFactoryBean(final Object factoryBean, Class<?> exposedType,
final ConfigurableBeanFactory beanFactory, final String beanName) {
try {
//获取对应的class
Class<?> clazz = factoryBean.getClass();
//判断是不是final的类
boolean finalClass = Modifier.isFinal(clazz.getModifiers());
//判断getObject是不是final的方法
boolean finalMethod = Modifier.isFinal(clazz.getMethod("getObject").getModifiers());
//两个都是final的
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.");
}
return createInterfaceProxyForFactoryBean(factoryBean, exposedType, beanFactory, beanName);
}
else {
//返回的值不是接口
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...
}
//其中有一个不是final的
return createCglibProxyForFactoryBean(factoryBean, beanFactory, beanName);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
上面的代码主要是分成三种情况:
- 对应的类是
final
和getObject
的方法也是final
,然后这个调用的方法的返回值接口的,这个时候就会调用createInterfaceProxyForFactoryBean(factoryBean, exposedType, beanFactory, beanName);
你会发现使用的jdk的动态的代理,具体的代码如下:
private Object createInterfaceProxyForFactoryBean(final Object factoryBean, Class<?> interfaceType,
final ConfigurableBeanFactory beanFactory, final String beanName) {
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);
});
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
上面的代码就是如果调用getObject
的方法就是从IOC容器中直接取。如果不是调用getObject
的方法,就直接调用。
-
对应的类是
final
和getObject
的方法也是final
,然后这个调用的方法的返回值不是接口,这个时候就直接返回factoryBean
-
对应的类和
getObject
的方法有一个不是final
的,就会调用createCglibProxyForFactoryBean(factoryBean, beanFactory, beanName);
方法,具体的代码如下:private Object createCglibProxyForFactoryBean(final Object factoryBean, final ConfigurableBeanFactory beanFactory, final String beanName) { 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; 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); } } //然后当调用的是getObject的方法的时候,返回的直接从容器中取得 ((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; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
上面的大概的介绍了FactoryBean的处理过程,就是配置类中的方法调用对应创建的FactoryBean的方法。具体的代码如下:
package com.ys.configurationTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration() public class AppConfig{ @Bean public B b() { //调用创建的FactoryBean的方法 myFactoryBean(); System.out.println("b init"); return new B(); } @Bean public MyFactoryBean myFactoryBean() { return new MyFactoryBean(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
还有最后一种情况,具体的代码如下:
package com.ys.configurationTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration() public class AppConfig{ @Bean public A a(){ System.out.println("a init"); b(); return new B(); } @Bean public B b() { System.out.println("b init"); return new B(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
这个时候我们继续看原来的代码,我只列出最重要的部分,具体的代码如下:
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs, MethodProxy cglibMethodProxy) throws Throwable { //省略部分代码。。。 //如果不是就是正常的方法,并不是处理FactoryBean的 判断是不是调用当前的工厂的方法 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())); } //是的话就直接调用父类的方法,也就是原始的创建的方法 return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs); } //不是的话,就会调用如下的方法 return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
走来判断当前执行的方法名是不是调用的方法名一样,很明显是的,于是就会调用父类的方法,这个时候会打印一句话a init,然后会执行 b();方法,于是和当前的调用的方法名的是不一样的,于是就会执行
resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName)
,具体的代码如下: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. 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; } } } 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) { String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked); beanFactory.registerDependentBean(beanName, outerBeanName); } return beanInstance; } finally { if (alreadyInCreation) { beanFactory.setCurrentlyInCreation(beanName, true); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
上面有一行很重要的代码就是getBean(),这儿还有一些细节,要等到讲Bean的生命周期的时候才会讲到。看完了
BeanMethodInterceptor
,我们再来看下BeanFactoryAwareMethodInterceptor
。
4.2BeanFactoryAwareMethodInterceptor
我们直接看对应的方法,具体的代码如下:
@Override
@Nullable
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//获取$$beanFactory属性
Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
Assert.state(field != null, "Unable to find generated BeanFactory field");
//取出方法中的BeanFactory的属性,设置给$$beanFactory
field.set(obj, args[0]);
//实际的(非CGLIB)超类是否实现BeanFactoryAware?
//如果是这样,则调用其setBeanFactory()方法。如果没有,请退出。
if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
return proxy.invokeSuper(obj, args);
}
return null;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
至此有关@Configuration
注解涉及到的所有的东西都讲完了。
5.写在最后
本篇博客主要讲了Spring注解的@Configuration
注解,以及一些处理的逻辑和流程,有一部分的东西,还要等到将Bean的生命周期才能讲到。