aop 实现有两种方式
1. ProxyFactoryBean方式: 这种方式是通过配置实现
2. ProxyFactory方式:这种方式是通过编程实现
这里说 ProxyFactoryBean ,先上一张ProxyFactoryBean 的关系图,后面能用到。
示例代码:
/**
* 代理接口,如果不是接口使用CGLIB代理
*/
public interface ProxyInterface {
void m();
void t();
}
/**
* 目标对象,接口的实现类
*/
public class Target implements ProxyInterface {
@Override
public void m() {
System.out.println("m");
}
@Override
public void t() {
System.out.println("t");
}
}
/**
* 通知器
*/
public class BeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("BeforeAdvice.....");
}
}
/**
* 通知器
*/
public class AfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("AfterAdvice.....");
}
}
定义一个接口ProxyInterface, 实现类为 Target,声明了两个advice,用来增强Target 方法。配置文件如下(advice 配置的顺序就是调用的顺序):
com.masz.springtest.aop.proxy.ProxyInterface
beforeAdvice
afterAdvice
测试:
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(AopTest.class, args);
//直接获取目标类
Target t = applicationContext.getBean(Target.class);
t.m();
//获取目标的代理。 关键的是:ProxyFactoryBean 是一个FactoryBean
ProxyInterface proxy = (ProxyInterface)applicationContext.getBean("targetProxy");
proxy.m();
System.exit(0);
}
运行结果:
m
BeforeAdvice.....
m
AfterAdvice.....
第一个方法没有被增强,第二个方法被增强了。
源码分析:
从代码中可以看到,通过applicationContext.getBean()获取ProxyFactoryBean, ProxyFactoryBean 是一个FactoryBean 所以getObject() 方法就是获取代理对象的入口方法。
ProxyFactoryBean.getObject() 源码:
@Override
@Nullable
public Object getObject() throws BeansException {
//初始化advisor 链
initializeAdvisorChain();
//对singleton 和 prototype 类型区分,生成相应的proxy
if (isSingleton()) {
//是singleton,调用此方法生成代理对象
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
//不是singleton,创建一个Prototype 的实例的代理对象
return newPrototypeInstance();
}
}
initializeAdvisorChain() 初始化 advisor chain:
/**
* 创建advisor 链。
* advisor 信息从BeanFactory 来的,每当创建一个新的prototype实例被创建时,BeanFactory 就会被刷新。
* 拦截器通过factory api 以编程的方式被添加,而且不受advisor改变的影响。
过程:
这个初始化advisor 链,是应用第一次通过 ProxyFactoryBean 获取代理对象时触发的,
advisor 链初始化完成之后,会读取配置中所有的通知器,这个读取比较简单就是调用容器的getBean()方法;
然后把获取的advice 加入到 advisor 链中,这个过程是addAdvisorOnChainCreation() 方法实现
*/
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
//这个是个标识位,标记通知器链是否已经初始化过了,如果已经初始化完了就直接返回。
if (this.advisorChainInitialized) {
return;
}
//配置的advice 不能是空的,如果没有配置advice就不用增强了。
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
//所有的bean 都是BeanFactory 管理的,所以BeanFactory不能是空
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
}
// Globals can't be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}
//遍历所有的advice 名称配置,获取advice bean 并且添加到 advisor 链
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
//interceptor name 是 * 结尾的
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
else {
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
//程序运行到这里就要检查添加的 interceptor 是 singleton 还是 prototype 类型。
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
//单例的 advice,就从beanFactory 中get bean 了。
advice = this.beanFactory.getBean(name);
}
else {
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
//prototype advice,要创建一个新的advice
advice = new PrototypePlaceholderAdvisor(name);
}
//添加advice 到 advisor chain
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
上面方法中的 addAdvisorOnChainCreation() 方法:
把配置 advice 封装成一个 DefaultPointcutAdvisor 对象,包含了PointCut(默认是Pointcut.TRUE) 和 advice。
然后把封装成的 advisor 放到 advisors 集合中,这个过程是在 类AdvisedSupport 中实现的,ProxyFactoryBean 是这个类的子类,看上图。
getSingletonInstance() 方法, 生成 singleton 代理对象。
/**
* Return the singleton instance of this class's proxy object,
* lazily creating it if it hasn't been created already.
* @return the shared singleton proxy
返回一个单例的代理对象,如果没有创建则会进行懒加载。
过程:首先读取ProxyFactoryBean 的配置,为生成代理对象做好准备,如:代理接口,目录对象等。
再通过AopProxy 生成代理对象。
*/
private synchronized Object getSingletonInstance() {
//如果已经创建了,就直接返回
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
//根据AOP 框架来判断需要代理的接口
Class> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
//设置代理对象的接口
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// Initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
//getProxy()方法,通过createAopProxy() 方法返回的AopProxy 得到代理对象。
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
/**
* getProxy() 方法出现了AopProxy 接口对象。
*/
protected Object getProxy(AopProxy aopProxy) {
return aopProxy.getProxy(this.proxyClassLoader);
}
上面代码中 createAopProxy() 返回的是一个AopProxy对象,这个对象有两个实现类:JdkDynamicAopProxy,CglibAopProxy,看到名字就很清楚了分别对应生成代理类不同的实现方式。getProxy() 方法调用AopProxy 类的getProxy() 方法返回代理对象。
Spring 使用AopProxy 接口对象把AOP代理的实现和框架其它部分区分开,体现面向接口编程。
createAopProxy() 方法是在ProxyFactoryBean 父类 ProxyCreatorSupport 中实现的,ProxyCreatorSupport 中又调用了AopProxyFactory 默认实现 DefaultAopProxyFactory.createAopProxy() 方法生成AopProxy 代理对象。
/**
* Subclasses should call this to get a new AOP proxy. They should not
* create an AOP proxy with {@code this} as an argument.
子类调用这个方法生成 AOP proxy。
在 AdvisedProxy 子类 ProxyFactoryBean 中通过 AopProxyFactory 来生成代理类,AdvisedProxy 封装了所有的生成代理对象信息,如:实现接口,目录类等。
AopProxyFactory 使用的是 DefaultAopProxyFactory,这个对象在 ProxyFactoryBean 父类 ProxyCreatorSupport 中被创建。
createAopProxy() 方法参数就是 AdvisedProxy 类型,这里传的是this,就是 ProxyFactoryBean,ProxyFactoryBean也是AdvisedProxy子类(可以查看上面的类关系图)。
*/
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
//这里是调用 AopProxyFactory 默认实现 DefaultAopProxyFactory.createAopProxy() 方法生成AopProxy 代理对象。
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
//目录对象的class
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.");
}
//targetClass 是接口类,使用 JDK来生成 Proxy
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
//如果不是接口类,使用CGLIB 生成代理对象
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
JdkDynamicAopProxy 源码分析:
JdkDynamicAopProxy 本身实现了 InvocationHandler 接口和 AopProxy 接口所以 JdkDynamicAopProxy实现的InvocationHandler.invoker() 方法就是Proxy 对象回调的方法。
实现的AopProxy.getProxy() 方法就是通过JDK动态代理生成的代理对象,传递的InvocationHandler 对象就是 JdkDynamicAopProxy 自身。
这就是动态代理了,切面的实惠就是在 invoke() 方法中体现的。后面再分析如何实现AOP。
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
//获取目标类上的接口并且判断是否需要添加SpringProxy Advised DecoratingProxy(spring4.3 新增) 接口
Class>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
//判断的目标对象实现的接口是否定义了equals或hashCode方法,
//在invoke() 方法调用的时候会对 equals 和 equals 做特殊的处理,参考后面
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//返回动态代理对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
总结:
通过AopProxy 对象封装target 目标对象之后,ProxyFactoryBean方法得到的对象已经是一个AopProxy代理对象了,在ProxyFactoryBean 中配置的target目标对象不会让应用直接调用其方法的实现,对target目标对象的方法调用会被AopProxy代理对象拦截,对于不同的AopProxy代理对象生成方式,会使用不同的拦截回调入口。对于 JDK的AopProxy代理对象,使用的是InvocationHander的invoker 回调入口。对于CGLIB的AopProxy代理对象,使用的是设置好的callbak 回调,在这里callback回调中,对于AOP的实现是通过DynamicAdvisedInterceptor 来完成的,DynamicAdvisedInterceptor 的回调入口是 intercept 方法(后面再分析CGLIB)。
这里只是AopProxy 代理对象的生成,通过这个过程把代理对象和拦截器待调用的部分都准备好。下面就分析AOP运行过程中对这些拦截器和代理对象的调用过程。
AOP 拦截器调用实现:
如果是JDK实现的代理对象就会通过InvocationHandler 来完成拦截器回调,如果是CGLIB 就通过DynamicAdvisedInterceptor 来完成回调。
JdkDynamicAopProxy 的 invoke 拦截:
在 JdkDynamicAopProxy.getProxy() 方法中,调用的的JDK动态代理生成代理类,JdkDynamicAopProxy 自身实现了InvocationHandler 接口,那么代理对象调用目标对象方法时会被invoke() 方法拦截
JdkDynamicAopProxy.invoke() 源码:
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
//从advised中获取目标对象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
//目标对象没有重写Object 的equals() 方法
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
//目标对象没有重写 Object的 hashCode() 方法
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
// 如果方法是在DecoratingProxy声明的,
// DecoratingProxy 只有getDecoratedClass() 一个方法,所有在这里直接调用
// 返回代理类的终极目标类。
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...
//Spring AOP不会增强直接实现Advised接口的目标对象。
//这里直接通过反射调用。
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
//返回值
Object retVal;
//是否暴露代理对象,如果暴露意味着在线程内共享代理对象,在线程内可通过AopContext 获取代理对象。就是通过ThreadLocal 实现的。
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
// 目标对象
target = targetSource.getTarget();
// 目标对象类
Class> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
//获取目标方法的拦截器链
List
注:
invoke 方法中获取调用拦截器链方法
List
JdkDynamicAopProxy AOP功能,就是通过 ReflectiveMethodInvocation 类实现的
ReflectiveMethodInvocation.proceed() 源码分析:
//这个方法是递归方法,当所有拦截器都执行完毕了,就通过反射调用目标方法返回。
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
//使用 currentInterceptorIndex 记录拦截器调用的下标,当所有拦截器都调用完毕后,通过反射调用目标方法。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//反射调用目标方法
return invokeJoinpoint();
}
//从拦截器链中获取一个拦截器,下标是 ++this.currentInterceptorIndex
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
//动态匹配
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
//如果方法和定义的切点匹配成功就执行
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
//执行到这里就是一个 MethodInterceptor , 则直接调用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
在示例代码中配置的是通知器,不是切面,如果配置的是切面就要走动态匹配了(动态匹配就是走jdk的正则匹配 MethodMatcher ,不扩展了)。
总结:每个 MethodInterceptor 对应的都有实现AfterReturningAdviceInterceptor, MethodBeforeAdviceInterceptor, ThrowsAdviceInterceptor。如 MethodBeforeAdviceInterceptor
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
则是调用完invoke() 方法后,就又调用了MethodInvocation.proceed() 方法,又回到了上一步方法中,这样一直循环调用,直到所有的interceptor 调用完毕。
总结:ProxyFactoryBean 通过jdk动态代理机制生成代理对象,当调用代理对象方法时,会被invoke() 方法拦截。在invoke() 方法中又获取了此方法的拦截器,通过对拦截器的调用实现了spring aop功能。CGLIB的实现只是生成代理对象的方式不同,这就让拦截器的入口有了变化。拦截器的生成和调用机制是一样的。看第二篇。
注:这里通过 initializeAdvisorChain(); 把advice 封装成了advisor,又如何把advisor 封装成具体的interceptor 呢? 看后续...