前言
通过之前的俩篇文章,我们大体上已经知道如何使用SpringAOP了,同时也了解到了SpringAOP底层使用的技术实现(JDK提供的动态代理和CGLib字节码增强技术)。至此,我们来想一个问题,SpringAOP到底是如何实现的呢?
猜测
首先我们知道SpringAOP运用的是代理模式,那么就一定是为目标对象生成一个代理对象,然后在一个合适的时机,将目标对象从IOC容器里替换成了我们已经加强过的代理对象。顺着这条思路我们来跟着源码进行解读。
本文中用到的代码示例
进行源码解读,可以通过debug来一步步分析。给出本次的代码示例,大家可以根据这份示例代码进行debug解读。
俩个service接口以及相关的实现类
public interface OrderService {
Order createOrder(String username, String product);
Order queryOrder(String username);
}
package com.suxin.aop.service.impl;
import com.suxin.aop.model.Order;
import com.suxin.aop.service.OrderService;
public class OrderServiceImpl implements OrderService {
private static Order order = null;
public Order createOrder(String username, String product) {
order = new Order();
order.setUsername(username);
order.setProduct(product);
return order;
}
public Order queryOrder(String username) {
return order;
}
}
public interface UserService {
User createUser(String firstName, String lastName, int age);
User queryUser();
}
package com.suxin.aop.service.impl;
import com.suxin.aop.model.User;
import com.suxin.aop.service.UserService;
public class UserServiceImpl implements UserService {
private static User user = null;
public User createUser(String firstName, String lastName, int age) {
user = new User();
user.setFirstName(firstName);
user.setLastName(lastName);
user.setAge(age);
return user;
}
public User queryUser() {
return user;
}
}
紧接着是俩个advice(增强):
package com.suxin.aop.advice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
import java.util.Arrays;
public class LogArgsAdvice implements MethodBeforeAdvice {
// 方法调用前输出 调用方法名字和参数
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("准备执行方法: "+ method.getName()+", 参数列表: " + Arrays.toString(args));
}
}
package com.suxin.aop.advice;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class LogResultAdvice implements AfterReturningAdvice {
// 方法调用后输出结果
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName()+"方法返回: " + returnValue);
}
}
然后进行XML配置:
<!-- 俩个接口的实现类纳入到IOC容器的管理里-->
<bean id="userServiceImpl" class="com.suxin.aop.service.impl.UserServiceImpl" />
<bean id="orderServiceImpl" class="com.suxin.aop.service.impl.OrderServiceImpl" />
<!-- 实现的俩个增强纳入到IOC容器管理里-->
<bean id="logArgsAdvice" class="com.suxin.aop.advice.LogArgsAdvice" />
<bean id="logResultAdvice" class="com.suxin.aop.advice.LogResultAdvice" />
<!-- 记录create*方法的传参-->
<bean id="logArgsAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="logArgsAdvice" /><!-- 设置增强-->
<property name="pattern" value="com.suxin.aop.service.*.create.*" /><!-- 正则匹配-->
</bean>
<!-- 记录query*方法的返回值-->
<bean id="logResultAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="logResultAdvice" /><!-- 设置增强-->
<property name="pattern" value="com.suxin.aop.service.*.query.*" /><!-- 正则匹配-->
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
以及main的运行代码:
package com.suxin.aop;
import com.suxin.aop.service.OrderService;
import com.suxin.aop.service.UserService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aops.xml");
UserService userService = (UserService)context.getBean("userServiceImpl");
userService.createUser("Tom","Paul",35);
userService.queryUser();
OrderService orderService = (OrderService)context.getBean("orderServiceImpl");
orderService.createOrder("DDD","买个糖葫芦");
orderService.queryOrder("DDD");
}
}
至此,示例代码就已经贴完了,沿用的是SpringAOP初始里的代码。大家可以参考这份示例代码进行debug调试。
贴一下控制台输出打印吧:
八月 15, 2019 10:36:38 上午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@685f4c2e: startup date [Thu Aug 15 10:36:38 CST 2019]; root of context hierarchy
八月 15, 2019 10:36:38 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [aops.xml]
准备执行方法: createUser, 参数列表: [Tom, Paul, 35]
queryUser方法返回: com.suxin.aop.model.User@77167fb7
准备执行方法: createOrder, 参数列表: [DDD, 买个糖葫芦]
queryOrder方法返回: com.suxin.aop.model.Order@1fe20588
解读
还记得XML配置里面将DefaultAdvisorAutoProxyCreator纳入到了SpringIOC容器的管理里面。它让我们的配置在IOC容器里的advisor(通知器)自动生效,我们来看一下这个类的继承图:
可以看到没,DefaultAdvisorAutoProxyCreator最终是一个实现了BeanPostProcessor接口的类,而该接口有俩个方法:
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
这俩个方法的执行时机在IOC创建bean的三个方法(createBeanInstance、populateBean和initializeBean)里的initializeBean方法里。看一下源码:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
// ......
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// postProcessBeforeInitialization方法的执行时机
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 调用bean配置里的inti-method="XXX"关联的方法
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()) {
// postProcessAfterInitialization执行的时机
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
通过源码我们可以看到,其实执行增强的时机就在postProcessAfterInitialization方法里,会在初始化bean的最后进行增强并且进行替换。
我们来看一下这块方法的实现(实现方法是在DefaultAdvisorAutoProxyCreator的父类AbstractAutoProxyCreator里面):
//来自于AbstractAutoProxyCreator,294行
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
//关注一下这个方法:如果需要,为 bean 生成代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
//深入到wrapIfNecessary方法里面来:
// 来自于AbstractAutoProxyCreator,333行
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;
}
// 获取对应这个bean需要的拦截器(其实就是各种通知器advisor)
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;
}
我们来看一下这个方法createProxy:
// 来自于AbstractAutoProxyCreator,437行
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//创建代理工厂实例
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// <aop:config proxy-target-class="true">......</aop:config>
// 是否不管有没有继承接口,都使用cglib技术
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 有接口的,调用一次或多次:proxyFactory.addInterface(ifc);
// 没有接口的,调用:proxyFactory.setProxyTargetClass(true);
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 所有跟bean相关的advisor(如果是advice或者interceptor都会包装成advisor)
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 继续关注这个方法
return proxyFactory.getProxy(getProxyClassLoader());
}
通过上面的源码解读我们可以知道上面的流程就是创建一个ProxyFactory,并且进行相关的属性赋值,然后通过是这个实例进行getProxy方法
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
先看createAopProxy方法:
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
继续看getAopProxyFactory()方法,发现返回的是一个DefaultAopProxyFactory,我们直接看createAopProxy这个方法。
// 来自于DefaultAopProxyFactory,50行
@Override
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)) {
// 返回JDK的AOP动态代理对象
return new JdkDynamicAopProxy(config);
}
// 返回CGLibd的AOP动态代理对象
return new ObjenesisCglibAopProxy(config);
}
else {
// 返回JDK的AOP动态代理对象
return new JdkDynamicAopProxy(config);
}
}
至此,我们就把重点放在了JdkDynamicAopProxy和ObjenesisCglibAopProxy上面
大家可以通过源码来看到JdkDynamicAopProxy是实现了InvocationHandler接口的类。
还是回到我们的源码解读进度来,返回了JdkDynamicAopProxy/ObjenesisCglibAopProxy对象以后开始调用createAopProxy方法。(我现在拿JdkDynamicAopProxy作为例子来看)
再把上面的代码拿下来回看一下
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
然后看到调用的是getProxy方法:
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 关注一下这里,是不是跟我们之前聊过的JDK提供的动态代理创建代理对象方法是一致的。
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
我们看到Proxy.newProxyInstance静态方法最后一个参数传的是this,也就是自身,因为JdkDynamicAopProxy也实现了InvocationHandler接口。
我们来看一下它是如何实现InvocationHandler接口方法invoke的:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// 如果设置了 exposeProxy,那么将 proxy 放到 ThreadLocal 中
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 创建一个 链,包含所有要执行的 advice
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 关注一下这里 先创建一个ReflectiveMethodInvocation 然后执行方法,得到返回值
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())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
有兴趣的朋友可以去看一下上面的ReflectiveMethodInvocation类里面的proceed方法,是一个递归回调。
至于ObjenesisCglibAopProxy其实也是继承CglibAopProxy,而 CglibAopProxy 继承了 AopProxy。有兴趣的自己去看一下吧,这里就不多说了。
小结一下吧:通过上面的分析,可以看出SpringAOP的生成代理对象以及替换时机是在BeanPostProcessor的postProcessAfterInitialization方法上。而创建代理涉及到了俩个类JdkDynamicAopProxy和ObjenesisCglibAopProxy。对应的之前说过的SpringAOP代理的实现是基于JDK提供的动态代理和CGLib技术实现。我们也分析了一下JdkDynamicAopProxy,它是一个继承了InvocationHandler接口方法的实现类。
多说几句,这篇文章可能要配合之前的SpringAOP俩篇文章看过之后再看,可能才得以理解。当然更需要点IOC容器的基础知识点。
网友评论