【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
AOP 基本概念
PointCut
切入点简单的理解就是定义了我们要切入的位置(在某些类 某些方法上切入)。因此Spring Aop的PointCut实现应该满足过滤得到目标类目标方法的需求。
从PointCut接口定义我们可以看到ClassFilter和MethodMatcher,ClassFilter判断那些类是要织入增强的,MethodMatcher是判断哪些方法是满足织入增强的。
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
Pointcut TRUE = TruePointcut.INSTANCE;
}
public interface ClassFilter {
/**
* 判断给定的clazz是否满足织入条件,满足则返回true
*/
boolean matches(Class<?> clazz);
/**
* Canonical instance of a ClassFilter that matches all classes.
* 这个默认的Filter是说所有的类都满足增强条件,都会返回true
*/
ClassFilter TRUE = TrueClassFilter.INSTANCE;
}
public interface MethodMatcher {
/**
* Perform static checking whether the given method matches.
仅仅对方法的静态匹配,不会检验方法具体参数值。
*/
boolean matches(Method method, Class<?> targetClass);
/**
*是否是进行运行时方法匹配
*/
boolean isRuntime();
/**
运行时 方法和方法参数同时都要进行匹配,满足则返回true
*/
boolean matches(Method method, Class<?> targetClass, Object... args);
/**
* Canonical instance that matches all methods.
* 默认所有的方法都匹配
*/
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
默认的pointcut实现有:NameMatchMethodPointcut,JdkRegexpMethodPointcut,AspectJExpressionPointcut等。这里对NameMatchMethodPointcut与AspectJExpressionPointcut做下简单介绍。
NameMatchMethodPointcut:仅仅通过对方法名字进行匹配织入位置。
其中从其父类StaticMethodMatcherPointcut源码可以看到如下代码,说明该pointcut会默认所有的类都满足要求,即不对类做过滤。
private ClassFilter classFilter = ClassFilter.TRUE;
public void setClassFilter(ClassFilter classFilter) {
this.classFilter = classFilter;
}
@Override
public ClassFilter getClassFilter() {
return this.classFilter;
}
AspectJExpressionPointcut:本身实现了MethodMatcher和Pointcut接口。该pointcut主要特点是支持AspectJ Expression。用户可以使用该语法定义poincut ,满足一些通配需求。

Advice
Advice就是在上面我们通过Pointcut定义好的位置织入的具体逻辑。Advice翻译过来叫做通知或者增强,这里我们统一叫做增强。增强 按照与业务代码执行顺序的先后位置主要分为三类:
BeforeAdvice:在业务代码执行之前执行我们织入的增强代码。这里BeforeAdvice接口去源码中看其实没有定义任何方法,是个空接口,我们在写具体的方法增强时是用的其子接口MethodBeforeAdvice。
AopAroundAdvice:在业务代码执行的前后织入增强代码。这种环绕增强spring借助aop alliance的MethodInterceptor实现。我们一般直接实现MethodInterceptor接口,实现我们增强代码即可。
AfterAdvice:在业务代码执行之后织入增强代码。和BeforeAdvice一样,它也是一个空接口。它具体又分为AfterReturningAdvice,ThrowsAdvice。一般我们实现直接实现AfterReturningAdvice接口即可。
Aspect/Advisor
spring 中的Aspect意思代表了一组poincut和advice,我们经常利用aspect注解定义一个类,然后通过
<aop:aspectj-autoproxy/>自动去发现该aspect。advisor是指一个pointcut和对应的advice。从范围上讲aspect包含了advisor。
这里介绍下默认的advisor DefaultPointcutAdvisor。

从类图接口继承上看 该默认的Advisor继承了Advisor 和PoincutAdvisor。Advisor是为了组装advice(增强),PointcutAdvisor在Advisor 接口基础上添加了Pointcut,定义了getPointcut接口。DefaultPointcutAdvisor可以看出一个对advisor和pointcut实现了getter/setter接口的类。
ProxyFactory/ProxyFactoryBean/AutoProxyCreator
AopProxy
这里叫做AopProxy不是很好,因为AopProxy是产生proxy的工具类,后面没有加Factory,也许Spring是为了避免与ProxyFactory冲突。AopProxy定义了getProxy方法。具体实现类有JdkDynamicAopProxy,ObjenesisCglibAopProxy(CglibAopProxy的扩展类)
这里在介绍AopProxy产生proxy的原理之前先提下AdvisedSupport。AdvisedSupport类图如下,它是AOP proxy配置管理的基类。

它里面维护了AOP proxy代理生产所需的配置,比如Advisors,TargetSource,AdvisorChainFactory。它的子类ProxyCreatorSupport实现了对AopProxy(JdkDynamicAopProxy,ObjenesisCglibAopProxy)具体类里的注入,实现代理创建功能。ProxyCreatorSupport是我们下面要介绍的ProxyFactory与ProxyFactoryBean的父类。
JdkDynamicAopProxy:这里我们介绍下Jdk动态生产代理的原理。JdkDynamicAopProxy实现了JDK InvocationHandler接口。我们先看下invoke方法具体代码
//invocationHandler接口实现
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 {
//对Object上的基本方法不处理。
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
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;
//判断是否把代理放到利用ThreadLocal实现的AOP上下文中
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 目标实例及目标类
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 得到我们注册的advice链,这一步很关键,它会根据我们的注册的pointcut来进行对目标类目标方法进行过滤,
// 判断方法是否满足定义的pointcut。下段代码我们具体分析
//如果chain为空说明不需要任何增强,
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()) {
//没有任何advice 直接对方法进行调用
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
//其中包含了代理类 目标对象 advice链 待调用方法。
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
//对advice进行调用。
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
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);
}
}
}
//同Proxy生成代理
@Override
public Object getProxy(ClassLoader classLoader) {
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
//类DefaultAdvisorChainFactory
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
//先根据ClassFilter来判断目标类是不是满足Pointcut要求
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
//取得方法拦截器
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
//获得pointcut上的MethodMatcher
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
//通过MethodMatcher来判断方法是否符合poincut定义的需求。
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
//如果是运行时MethodMatcher则需要对方法参数值进行匹配。
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
因为JdkDynamicAopProxy采用JDK动态代理原理 它只能对实现相应接口的类进行代理,不能对没有接口的实现类进行代理。
ObjenesisCglibAopProxy:CglibAOpProxy采用Cglib库通过Enhancer来对类字节码修改,实现AOP增强。CligbAopProxy可以对没有接口类进行代理,但不能对final类或方法继续代理。
ProxyFactory
AOP proxies 代理工厂,主要是为了编程( programmatic use)方式获取proxy,而不是通过一个Bean Factory去获取。ProxyFactory为aop proxy提供了简单的配置和获取方法。
下面我看一个简单的例子
//定义一个advice
public class AopMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before "+method.getName()+"-------");
}
}
// action
public interface HelloAction {
public String sayHello(String name);
public String sayHelloA(String name);
}
//impl
public class HelloActionImpl implements HelloAction {
@Override
public String sayHello(String name) {
System.out.println("hello "+name);
return "hello "+name;
}
@Override
public String sayHelloA(String name) {
System.out.println("helloA "+name);
return "helloA "+name;
}
}
// ProxyFactoryTest
public class ProxyFactoryTest {
@Test
public void testGetProxy(){
ProxyFactory proxyFactory=new ProxyFactory();
//pointcut 匹配sayHello方法
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedNames(new String[] {"sayHello"});
//define advisor (pointcut + advice)
DefaultPointcutAdvisor beforeAdvisor=new DefaultPointcutAdvisor(pointcut,new AopMethodBeforeAdvice());
HelloAction helloActionTarget=new HelloActionImpl();
//这样就可以采用JDK proxy生成方法
proxyFactory.setInterfaces(HelloAction.class);
proxyFactory.setTarget(helloActionTarget);
proxyFactory.addAdvisor(beforeAdvisor);
HelloAction proxy=(HelloAction)proxyFactory.getProxy();
proxy.sayHello("yao");
proxy.sayHelloA("yaoA");
}
}
我们debug进去看看一个aop 代理是如何运行的
首先构造父类ProxyCreatorSupport,前面我们介绍过,主要是增加属性AopProxyFactory,生成一个AopPorxy(用来生产代理)

DefaultAopProxyFactory主要是根据有无接口来生产JDK or Cglib AopProxy

然后通过生成的AopProxy getProxy即获取到代理对象。代理对象织入了advisor,具体执行就调用了我们上面分析的JDK invoke 方法。(这里假设采用JDK动态代理)
ProxyFactoryBean
ProxyFactoryBean和ProxyFactory功能一样,只不过ProxyFactoryBean实现了FactoryBean,与Spring IOC容器结合起来了。下面是其类图,它并实现了BeanFactoryAware感知接口,实现BeanFactory的自动注入。与ProxyFactory一样都是ProxyCreatorSupport子类。

我们重点看下其getObject接口,

先判断是否是产生单例代理还是原型代理
产生单例代理就存下来,下次直接利用。具体过程都是先判处产生 createAopProxy(JDK or Cglib)然后getProxy即可。
原型的是每次连ProxyCreatorSupport都是新生成的,然后在createAopProxy,最后getProxy即可。


getProxy

总之 ProxyFactoryBean的主要目的就是把Aop 嵌入到IOC 容器中。
AutoProxyCreator
上面我们讲了这么多都是针对一个目标一个目标配置的,如果目标很多怎么办呢?这里Spring IOC容器通过BeanPostProcessor 来实现Aop 代理自动创建,BeanPostProcessor。常见的自动代理创建有BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator。我们看看默认的DefaultAdvisorAutoProxyCreator的类图

AbstractAutoProxyCreator实现了BeanPostProcessor的postProcessBeforeInstantiation

AbstractAutoProxyCreator的createProxy方法。采用ProxyFactory实现。

这里测试用例就不写了,文章还有很多介绍不全,慢慢修正补充。
本文链接:http://my.oschina.net/robinyao/blog/649518
来源:oschina
链接:https://my.oschina.net/u/223302/blog/649518