面向方面編程(AOP)補(bǔ)充了面向?qū)ο缶幊?OOP)璧南,提供了另一種思考程序結(jié)構(gòu)的方式存筏。OOP中模塊化的關(guān)鍵單元是類,而AOP中模塊化的單元是方面浴讯。 方面可以實(shí)現(xiàn)關(guān)注點(diǎn)的模塊化,比如跨越多個(gè)類型和對象的事務(wù)管理蔼啦。(在AOP文獻(xiàn)中榆纽,這種關(guān)注點(diǎn)通常被稱為橫切關(guān)注點(diǎn)。)
簡述Spring AOP實(shí)現(xiàn)
在之前BeanFactory及ApplicationContext的源碼分析中都有提到過,Spring AOP的實(shí)現(xiàn)是通過實(shí)現(xiàn)BeanPostProcessor
接口奈籽,在前置或者后置方法中饥侵,通過返回代理對象,完成AOP的實(shí)現(xiàn)衣屏。這里實(shí)現(xiàn)一個(gè)簡單的BeanPostProcessor:
public class LogInterceptor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof UserService) {
UserService us = (UserService) bean;
Object proxyInstance = Proxy.newProxyInstance(LogInterceptor.class.getClassLoader(), new Class[]{UserService.class},
(proxy, method, args) -> {
System.out.println("LogInterceptor UserService: " + method.getName() + " invoked");
return method.invoke(us, args);
});
return proxyInstance;
}
return bean;
}
}
LogInterceptor
是一個(gè)簡單的日志攔截器躏升,在bean
構(gòu)建過程中,init之后狼忱,就會遍歷所有的BeanPostProcessor的postProcessAfterInitialization方法煮甥,當(dāng)檢測到當(dāng)前bean是UserService
實(shí)例時(shí),就會返回一個(gè)代理對象藕赞,代理對象在原對象每個(gè)方法調(diào)用時(shí)都會打印一行日志成肘,這樣一個(gè)簡單的日志攔截器就完成了。
運(yùn)行程序
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService.getName());
System.out.println(userService.getMoney());
System.out.println(userService.getIntegral());
得到輸出
LogInterceptor UserService: getName invoked
Hello World
LogInterceptor UserService: getMoney invoked
999
LogInterceptor UserService: getIntegral invoked
998
可以看到斧蜕,只要實(shí)現(xiàn)BeanPostProcessor
双霍,在實(shí)現(xiàn)接口方法類完成對想要增強(qiáng)bean攔截,然后完成需要的增強(qiáng)處理批销,就可以了洒闸。當(dāng)然上例只是簡單的接口代理,對于有些沒有接口的bean均芽,就需要CGlib完成代理了丘逸。
Spring AOP實(shí)現(xiàn)
當(dāng)然如果每次增強(qiáng)操作都要這樣手動處理就太麻煩了,還要考慮沒有接口的類掀宋,所以Spring內(nèi)部實(shí)現(xiàn)了AOP以簡化開發(fā)深纲。
Spring實(shí)現(xiàn)AOP的方式有兩種,一種為ProxyFactoryBean
劲妙,對單個(gè)bean做代理湃鹊;另一種為BeanPostProcessor
,根據(jù)規(guī)則镣奋,對一類bean做代理币呵。
ProxyFactoryBean
ProxyFactoryBean是用于創(chuàng)建代理類的通用FactoryBean,通過配置侨颈,可以在構(gòu)建bean的時(shí)候返回代理對象余赢,而代理對象通過對 target 對象進(jìn)行增強(qiáng),這樣在執(zhí)行bean方法的時(shí)候就可以達(dá)到想要的增強(qiáng)后的效果哈垢。示例
spring-aop.xml 文件
<!--攔截器-->
<bean id="debugInterceptor" class="com.zero.demo.advice.DebugInterceptor"/>
<!--target-->
<bean id="mockTask" class="com.zero.demo.aop.MockTask"/>
<bean id="task" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="com.zero.demo.aop.ITask"/>
<property name="target" ref="mockTask"/>
<property name="interceptorNames">
<list>
<value>debugInterceptor</value>
</list>
</property>
</bean>
main方法
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader configReader = new XmlBeanDefinitionReader(beanFactory);
configReader.loadBeanDefinitions("classpath:spring-aop.xml");
ITask task = beanFactory.getBean("task", ITask.class);
task.execute();
}
可以通過調(diào)試進(jìn)入beanFactory#getBean
方法妻柒,查看bean的構(gòu)建,在AbstractBeanFactory#doGetBean
方法內(nèi)
if (mbd.isSingleton()) {
// 構(gòu)建bean温赔,實(shí)際構(gòu)建的是ProxyFactoryBean bean
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
// 根據(jù)是否是FactoryBean蛤奢,構(gòu)建proxy對象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
對于FactoryBean鬼癣,最后容器中存放的是FactoryBean#getObject
方法獲得的對象,在getObjectForBeanInstance
方法內(nèi)會根據(jù) sharedInstance 是否為FactoryBean啤贩,然后決定是否調(diào)用getObject方法獲取代理的對象待秃。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 到這里說明一定是一個(gè)FactoryBean
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 從工廠返回bean實(shí)例。
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
getObjectFromFactoryBean
方法主要是創(chuàng)建bean以及創(chuàng)建之后的處理痹屹,創(chuàng)建bean的方法為doGetObjectFromFactoryBean
章郁,這是從給定的FactoryBean獲取要公開的對象的方法,核心邏輯就是factory.getObject()
志衍,也就是ProxyFactoryBean
的getObject
方法
public Object getObject() throws BeansException {
// 創(chuàng)建advisor(interceptor)鏈暖庄。根據(jù)interceptorNames,從BeanFactory取出相應(yīng)的advisor(interceptor)
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn(...);
}
return newPrototypeInstance();
}
}
先創(chuàng)建advisor(interceptor)鏈楼肪。根據(jù)interceptorNames培廓,從BeanFactory取出相應(yīng)的advisor(interceptor),然后getSingletonInstance
方法主要是調(diào)用createAopProxy
方法創(chuàng)建AopProxy春叫,然后調(diào)用返回的aopProxy的getProxy方法肩钠,獲取最后的proxy對象。createAopProxy
方法的調(diào)用DefaultAopProxyFactory#createAopProxy
方法暂殖,返回AopProxy對象
//DefaultAopProxyFactory#createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 判斷使用ObjenesisCglibAopProxy還是JdkDynamicAopProxy
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException(...);
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
根據(jù)條件判斷是返回ObjenesisCglibAopProxy
還是JdkDynamicAopProxy
价匠,
// JdkDynamicAopProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
... log ..
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
newProxyInstance方法InvocationHandler參數(shù)傳的是this
,也就是說呛每,方法調(diào)用會調(diào)用自身的invoke方法
// JdkDynamicAopProxy#invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
... equal踩窖、hashCode 等等
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 獲取此方法的攔截鏈。之前初始化過
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 創(chuàng)建一個(gè)方法調(diào)用
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(...);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
當(dāng)攔截鏈不為空晨横,則創(chuàng)建一個(gè)ReflectiveMethodInvocation洋腮,調(diào)用其proceed方法,proceed方法的調(diào)用會遞歸調(diào)用颓遏,直到所有的MethodInterceptor調(diào)用完
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// currentInterceptorIndex索引遞增徐矩,每次調(diào)用將獲取下一個(gè)MethodInterceptor
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 動態(tài)方法匹配
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 遞歸調(diào)用
return proceed();
}
}
else {
// methodInterceptor傳參為this,只要methodInterceptor內(nèi)調(diào)用proceed方法叁幢,將遞歸調(diào)用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
這樣Spring AOP攔截鏈就調(diào)用完畢。
BeanPostProcessor
Spring更為常見的AOP使用是BeanPostProcessor
坪稽,使用BeanPostProcessor
可以通過名稱或者正則表達(dá)式曼玩,更加便捷的對一類bean進(jìn)行AOP操作。下面是簡單xml配置
<bean id="debugInterceptor" class="com.zero.demo.advice.DebugInterceptor"/>
<bean id="logInterceptor" class="com.zero.demo.advice.LogInterceptor"/>
<bean id="task" class="com.zero.demo.aop.MockTask"/>
<bean id="processor" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="task,*Service,*Dao"/>
<property name="interceptorNames">
<list>
<value>debugInterceptor</value>
<value>logInterceptor</value>
</list>
</property>
</bean>
示例是使用BeanNameAutoProxyCreator
窒百,根據(jù)名稱自動匹配黍判,名稱可以用通配符。main函數(shù)如下
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader configReader = new XmlBeanDefinitionReader(beanFactory);
configReader.loadBeanDefinitions("classpath:spring-aop.xml");
// 因?yàn)槭褂玫氖莃eanFactory篙梢,所以需要手動注冊BeanPostProcessor顷帖,ApplicationContex會自動注冊
BeanPostProcessor processor = beanFactory.getBean("processor", BeanPostProcessor.class);
beanFactory.addBeanPostProcessor(processor);
ITask task = beanFactory.getBean("mockTask", ITask.class);
task.execute();
}
這里使用的BeanPostProcessor是BeanNameAutoProxyCreator
,BeanNameAutoProxyCreator
實(shí)現(xiàn)了SmartInstantiationAwareBeanPostProcessor
接口
SmartInstantiationAwareBeanPostProcessor
的繼承關(guān)系及方法
SmartInstantiationAwareBeanPostProcessor
及繼承的接口都會影響bean的構(gòu)建,所以實(shí)際上只要看看BeanNameAutoProxyCreator
對SmartInstantiationAwareBeanPostProcessor
接口的實(shí)現(xiàn)即可贬墩。
其中榴嗅,直接可以返回代理bean的方法有
- postProcessBeforeInstantiation,在bean構(gòu)建開始之前攔截
- postProcessBeforeInitialization陶舞,在bean init之前攔截
- postProcessAfterInitialization嗽测,在bean init之后攔截
其他的方法主要是bean的類型,構(gòu)造函數(shù)以及屬性注入等肿孵。
postProcessBeforeInstantiation
方法
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 如果我們有一個(gè)定制的TargetSource唠粥,在這里創(chuàng)建代理。
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 創(chuàng)建proxy
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
也就是xml文件中配置了customTargetSourceCreators
屬性停做,則會在bean的構(gòu)建之前攔截晤愧。createProxy
是核心創(chuàng)建代理的方法,后面詳細(xì)分析蛉腌。
postProcessBeforeInitialization
方法直接返回傳入的bean官份,無其他邏輯
postProcessAfterInitialization
方法
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && 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;
}
// 如果有advice,創(chuàng)建代理眉抬。
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;
}
postProcessAfterInitialization
方法如果有advice贯吓,則創(chuàng)建代理,創(chuàng)建代理的邏輯和postProcessBeforeInstantiation
方法類似蜀变,下面重點(diǎn)看一下createProxy
方法
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
可以看到核心邏輯有3處
- 創(chuàng)建ProxyFactory:ProxyFactory proxyFactory = new ProxyFactory();
- 獲得advisors:Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
- 構(gòu)建代理:return proxyFactory.getProxy(getProxyClassLoader());
ProxyFactory
的getProxy
方法其實(shí)和前面介紹的ProxyFactoryBean
類似悄谐,ProxyFactory
和ProxyFactoryBean
共同繼承ProxyCreatorSupport
,實(shí)現(xiàn)代理的邏輯都來自于超類ProxyCreatorSupport
库北。
Spring 事務(wù)
稍帶提一句爬舰,Spring 事物的攔截處理主要由TransactionInterceptor
實(shí)現(xiàn)。