@Configuration的底层实现
上面的文章中已经大致解析了@Configuration的实现,对于cglib代理之外的解析已经很完善了,不过并没有细致分析其中的cglib动态代理,现在在这里只会关注其中对于cglib动态代理的实现。
这里会先简单介绍以下cglib动态代理
cglib动态代理
假设有下面的需要代理的目标对象
public class Target {
public void test(){
System.out.println("test");
}
}
代理的逻辑可以写在实现MethodInterceptor的对象中,具体在intercept
方法中会有其中的代理逻辑
public class MyMethodInterceptor implements MethodInterceptor {
/**
*
* @param o 目标实例对象
* @param method
* @param objects 方法的参数
* @param methodProxy 代理对象的方法,就是下面的方法,相当于方法自身
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// 代理逻辑
System.out.println("代理逻辑");
// 执行父类的方法,就是目标对象的原生方法,返回返回值
return methodProxy.invokeSuper(o,objects);
}
}
测试
public static void main(String[] args) {
// 先创建一个代理对象
Enhancer enhancer = new Enhancer();
// 要代理的对象的class
enhancer.setSuperclass(Target.class);
// 设置代理的回调,也就是代理的逻辑,Callback的实现类
enhancer.setCallback(new MyMethodInterceptor());
// 获得最终的代理对象
Target target = (Target) enhancer.create();
target.test();
}
spring中的cglib动态代理
在bean工厂后置处理器的回调方法中enhanceConfigurationClasses是处理cglib动态代理的,而其中的enhance方法则是生成代理对象的。
org.springframework.context.annotation.ConfigurationClassEnhancer#enhance
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
//判断是否被代理过
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;
}
//通过newEnhancer返回一个cglib代理对象
//在这个new的过程也是spring对需要代理的中的方法和属性的处理
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
if (logger.isDebugEnabled()) {
logger.debug(String.format("Successfully enhanced %s; enhanced class name is: %s",
configClass.getName(), enhancedClass.getName()));
}
return enhancedClass;
}
在newEnhancer
方法中会真正创建其代理对象的Enhancer对象,需要关注其中的CALLBACK_FILTER,这个执行代理逻辑的对象是ConfigurationClassEnhancer的内部类BeanMethodInterceptor。
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
//先创建一个代理对象
Enhancer enhancer = new Enhancer();
//要代理的对象的class
enhancer.setSuperclass(configSuperClass);
//设置一个接口
//便于增强
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
//设置名字的生成策略
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
//BeanFactoryAwareGeneratorStrategy是一个生成策略
//主要为生成的cglib类中添加成员变量$$beanFactory
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
//过滤方法,不能每次都去new
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor
在这个对象的intercept
方法就会处理
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
// 拿到此时生成bd的beanName
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// Determine whether this bean is a scoped-proxy
Scope scope = AnnotatedElementUtils.findMergedAnnotation(beanMethod, Scope.class);
if (scope != null && scope.proxyMode() != ScopedProxyMode.NO) {
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.
// 下面直接通过getBean方法创建对象
// 一般情况不会进入,特殊的bd
if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
factoryContainsBean(beanFactory, beanName)) {
// 实例化bean,拿到bean对象
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);
}
}
// 判断当前方法实例化的bean是不是外部方法
// 如果当前方法是@Bean注解方法中的方法,那么此时实例化的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.isWarnEnabled() &&
BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
logger.warn(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
return 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;
}
}
}
// 同样是通过getBean拿到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) {
String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
beanFactory.registerDependentBean(beanName, outerBeanName);
}
return beanInstance;
}
finally {
if (alreadyInCreation) {
beanFactory.setCurrentlyInCreation(beanName, true);
}
}
}
上面的方法中大致的逻辑如下
- 判断是不是方法内部方法,不过如果是第一次调用那么一定是外部方法,那么会调用原生方法初始化bean对象。
- 在执行原生方法时可能会执行其他实例化bean的方法,此时就会再次进入
intercept
方法,并且再次判断是不是方法内部方法,此时一定是,那么会resolveBeanReference
方法实例化对象,最终会通过getBean
方法实例化对象。这里的getBean
方法并不是单纯调用@Bean注解的实例化方法,可以说是直接从单例池map中拿到bean对象。这个方法的详细分析可以参考《bean初始化(实例化)详解》和《spring的循环依赖分析》中对getBean
方法的解析。