说到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注解标识的类会使用代理,可以保证生成的对象是单例的,我们在开发中可以好好利用这个特性。