spring 依賴注入時,什麼時候會建立代理類
問題來源
以前一直有個疑惑,為什麼我建立的controller中注入的service類有時候是代理類,有時候是普通javabean,當時能力不夠,現在已經有了點經驗就大膽跟了跟原始碼,看看到底咋回事。
首先看看問題現象:
a1:service是代理類,並且是CGLIB型別代理
a2:service是代理類,並且是jdk 動態代理
b:serivce不是代理類,而是普通類
問題分析
我對service類進行了以下的測試:(前提開啟事務註解<tx:annotation-driven/>)
1)service方法新增@Transactional註解或者加入其它的aop攔截配置,沒有實現任何介面。 對應問題現狀 a1
2)service方法新增@Transactional註解或者加入其它的aop攔截配置,實現了介面。 對應問題現狀a2
3)serice方法沒有新增@Transactional註解或者其它的aop攔截配置。 對應問題現狀b
看來出現這種問題的原因就是spring的問題,因為這個類是它建立的,這就需要我們來看下spring建立bean的程式碼,由於spring太龐大了
我們只看最關鍵的部分,在建立bean是都會呼叫getBean()方法,
@SuppressWarnings("unchecked") protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { return createBean(beanName, mbd, args); }
經過不斷的流轉會進入AbstractAutowireCapableBeanFactory的createBean方法
@Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {try { Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { // A previously detected exception with proper bean creation context already, // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry. throw ex; } }
然後呼叫doCreateBean方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; }// Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } }return exposedObject; }
然後進入核心的createBeanInstance方法,省去了不相關方法
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// No special handling: simply use no-arg constructor. return instantiateBean(beanName, mbd); }
然後呼叫instantiateBean進行bea的例項化
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this; if (System.getSecurityManager() != null) { beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, parent), getAccessControlContext()); } else { beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); } BeanWrapper bw = new BeanWrapperImpl(beanInstance); initBeanWrapper(bw); return bw; } catch (Throwable ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); } }
例項化時會呼叫SimpleInstantiationStrategy的instantiate方法
@Override public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // Don't override the class with CGLIB if no overrides. if (!bd.hasMethodOverrides()) { Constructor<?> constructorToUse; synchronized (bd.constructorArgumentLock) { constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; if (constructorToUse == null) { final Class<?> clazz = bd.getBeanClass(); if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { if (System.getSecurityManager() != null) { constructorToUse = AccessController.doPrivileged( (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor); } else { constructorToUse = clazz.getDeclaredConstructor(); } bd.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Throwable ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } return BeanUtils.instantiateClass(constructorToUse); } else { // Must generate CGLIB subclass. return instantiateWithMethodInjection(bd, beanName, owner); } }
該方法就是真正的例項化bean,根據不同情況通過CGLIB的方式
instantiateWithMethodInjection(bd, beanName, owner)
或者java的反射方式
BeanUtils.instantiateClass(constructorToUse)
例項化一個bean,這是時候都是一個純潔無瑕的javabean,那每個bean的額外加工,例如為某個bean新增事務支援,
新增aop配置,還有就是將springmvc的controller進行url和handler的對映,等等這些都是在spring的擴充套件點完成的,回到
上面的doCreateBean方法
執行完例項化bean後執行
populateBean(beanName, mbd, instanceWrapper); initializeBean(beanName, exposedObject, mbd);
其中的populateBean是為了給生成的bean裝配屬性,這不是我們這次討論的重點,關鍵是initializebean方法
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
這個方法就是對生成的bean進行一些擴充套件處理,主要是這個方法就,會呼叫我們自定義的擴充套件點
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { Object current = beanProcessor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
可以看到這裡是獲取所有的beanProcessor,呼叫postProcessAfterInitialization方法,我們要關注是的一個叫InfrastructureAdvisorAutoProxyCreator
的擴充套件類。
/** * Auto-proxy creator that considers infrastructure Advisor beans only, * ignoring any application-defined Advisors. * * @author Juergen Hoeller * @since 2.0.7 */ @SuppressWarnings("serial") public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {}
看下這個類的註釋可以發現這個類是為配置了aop配置(包括註解和xml配置兩種方式)的類,生成代理類。
核心方法是下面這個方法wrapIfNecessary方法。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
下面解析下這個函式
首先看下getAdvicesAndAdvisorsForBean這個方法:名字很明顯用來獲取當前bean的advisor和adices的,這些都是生成代理類時需要的資訊。
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) { List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); }
然後呼叫findEligibleAdvisors,獲取配置的advisor資訊
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = findCandidateAdvisors(); List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
來看下findCandidateAdvisors方法,最終呼叫BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans
public List<Advisor> findAdvisorBeans() { // Determine list of advisor bean names, if not cached already. String[] advisorNames = null; synchronized (this) { advisorNames = this.cachedAdvisorBeanNames; if (advisorNames == null) { // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the auto-proxy creator apply to them! advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } } if (advisorNames.length == 0) { return new LinkedList<>(); } List<Advisor> advisors = new LinkedList<>(); for (String name : advisorNames) { if (isEligibleBean(name)) { if (this.beanFactory.isCurrentlyInCreation(name)) { } else { try { advisors.add(this.beanFactory.getBean(name, Advisor.class)); } catch (BeanCreationException ex) { throw ex; } } } } return advisors; }
1)首先獲取spring管理的Advisor型別的類名稱。
2)通過beanFactory獲取該bean對應的實體類,並裝入advisors。
生成的這個advisor可是相當複雜,這裡我們以事務advisor為例說明
可以看到這個advisor包含了advice(aop中的通知),pointcut(aop中的切入點),
advice是TransactionInterceptor,這個通知是用來管理spring的事務的可以看到包含事務的管理器等管理事務的屬性,具體的方法見TransactionAspectSupport.invokeWithinTransaction pointcut是TransactionAttributeSourcePointcut,
public boolean matches(Method method, @Nullable Class<?> targetClass) { if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) { return false; } TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); }
這個是pointcut的核心方法,用來匹配某個類是否符合事務管理的aop攔截要求。 ok,回到之前的wrapIfNecessary方法
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
我們之前分析道getAdvicesAndAdvisorsForBean方法,可以看到如果得到的結果是DO_NOT_PROXY,就會將這個bean直接返回,
如果不是DO_NOT_PROXY,(其實DO_NOT_PROXY就是null,但是使用DO_NOT_PROXY會使得程式碼邏輯更加清晰),就會執行
createProxy方法,建立一個代理類,然後返回一個代理類,ok,現在我們就清楚了問題分析中的 第3)和第 1) 2) 區別,那就是
service類是否配置了相關的aop攔截配置,無論是註解還是xml形式,目前我們還不清楚第1)和 第2)的區別,就是為什麼有時候
生成jdk代理,有時候生成cglib代理,這就需要繼續向下看creatProxy方法了,最終會進入一個DefaultAopProxyFactory的createAopProxy
方法:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }
如果目標類是介面就一定會使用jdk代理,如果目標類沒有可以代理的介面就一定會使用Cglib代理。