源码参考:github上的code4craft/tiny-spring
项目。
tiny-spring-step-10-invite-cglib-and-aopproxy-factory
文章目录
源码解析
警告:请参考github上的源码,不然理解起来比较困难。
- 切点(Pointcut)和通知(Advice)
- 整合到Spring容器中
目录结构
- AbstractAopProxy
实现AopProxy,依赖了代理的元数据信息。 - AdvisedSupport
代理的元数据信息,记录对哪个对象的哪个方法进行了增强。 - Advisor
通知器的抽象,管理通知 - AopProxy
AOP代理的抽象 - AspectJAroundAdvice
通知的具体实现 - AspectJAwareAdvisorAutoProxyCreator
将代理整合到spring中,使用了BeanPostProcessor, BeanFactoryAware - AspectJExpressionPointcut
切点的具体实现 - AspectJExpressionPointcutAdvisor
切点通知器的实现,管理切点和通知 - BeanFactoryAware
提供BeanFactory - Cglib2AopProxy
Cglib的AopProxy实现 - ClassFilter
类过滤器抽象 - JdkDynamicAopProxy
Jdk的AopProxy实现 - MethodMatcher
方法匹配抽象 - Pointcut
切点抽象 - PointcutAdvisor
切点通知器抽象 - ProxyFactory
Proxy创建工厂 - ReflectiveMethodInvocation
方法处理,Joinpoint的具体实现 - TargetSource
目标对象的信息
切点(Pointcut)
Pointcut是对AOP对切点的高级抽象。主要作用是类的过滤以及方法的匹配
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
public interface MethodMatcher {
boolean matches(Method method, Class targetClass);
}
public interface ClassFilter {
boolean matches(Class targetClass);
}
实现类:AspectJExpressionPointcut
public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {
private PointcutParser pointcutParser;
private String expression;
private PointcutExpression pointcutExpression;
private static final Set<PointcutPrimitive> DEFAULT_SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>();
static {
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET);
}
public AspectJExpressionPointcut() {
this(DEFAULT_SUPPORTED_PRIMITIVES);
}
public AspectJExpressionPointcut(Set<PointcutPrimitive> supportedPrimitives) {
pointcutParser = PointcutParser
.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives);
}
protected void checkReadyToMatch() {
if (pointcutExpression == null) {
pointcutExpression = buildPointcutExpression();
}
}
private PointcutExpression buildPointcutExpression() {
return pointcutParser.parsePointcutExpression(expression);
}
public void setExpression(String expression) {
this.expression = expression;
}
@Override
public ClassFilter getClassFilter() {
return this;
}
@Override
public MethodMatcher getMethodMatcher() {
return this;
}
@Override
public boolean matches(Class targetClass) {
checkReadyToMatch();
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
@Override
public boolean matches(Method method, Class targetClass) {
checkReadyToMatch();
ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
if (shadowMatch.alwaysMatches()) {
return true;
} else if (shadowMatch.neverMatches()) {
return false;
}
// TODO:其他情况不判断了!见org.springframework.aop.aspectj.RuntimeTestWalker
return false;
}
}
管理切点的工具:PointcutAdvisor
public interface PointcutAdvisor extends Advisor{
//切点通知器管理了切点和通知
Pointcut getPointcut();
}
通知(Advice)
Advice是对AOP的高层级抽象,主要作用的增强逻辑的实现。advice的实现是MethodInterceptor
通知器:管理通知的工具
public interface Advisor {
Advice getAdvice();
}
相关方法的调用关系
AOP代理
是对代理的高级抽象
public interface AopProxy {
Object getProxy();
}
抽象实现类
public abstract class AbstractAopProxy implements AopProxy {
protected AdvisedSupport advised;
public AbstractAopProxy(AdvisedSupport advised) {
this.advised = advised;
}
}
JDK具体的实现
public class JdkDynamicAopProxy extends AbstractAopProxy implements InvocationHandler {
public JdkDynamicAopProxy(AdvisedSupport advised) {
super(advised);
}
@Override
public Object getProxy() {
return Proxy.newProxyInstance(getClass().getClassLoader(), advised.getTargetSource().getInterfaces(), this);
}
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
MethodMatcher methodMatcher = advised.getMethodMatcher();
if (methodMatcher!= null && methodMatcher.matches(method, advised.getTargetSource().getTarget().getClass())) {
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(),method, args));
} else {
return method.invoke(advised.getTargetSource().getTarget(), args);
}
}
}
CGLIB具体实现
public class Cglib2AopProxy extends AbstractAopProxy {
public Cglib2AopProxy(AdvisedSupport advised) {
super(advised);
}
@Override
public Object getProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(advised.getTargetSource().getTargetClass());
//getInterfaces() 获得这个对象所实现的所有接口
enhancer.setInterfaces(advised.getTargetSource().getInterfaces());
enhancer.setCallback(new DynamicAdvisedInterceptor(advised));
Object enhanced = enhancer.create();
return enhanced;
}
private static class DynamicAdvisedInterceptor implements MethodInterceptor {
private AdvisedSupport advised;
private org.aopalliance.intercept.MethodInterceptor delegateMethodInterceptor;
private DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
this.delegateMethodInterceptor = advised.getMethodInterceptor();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (advised.getMethodMatcher() == null|| advised.getMethodMatcher().matches(method, advised.getTargetSource().getTargetClass())) {
return delegateMethodInterceptor.invoke(new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, args, proxy));
}
return new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, args, proxy).proceed();
}
}
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
private final MethodProxy methodProxy;
public CglibMethodInvocation(Object target, Method method, Object[] args, MethodProxy methodProxy) {
super(target, method, args);
this.methodProxy = methodProxy;
}
@Override
public Object proceed() throws Throwable {
return this.methodProxy.invoke(this.target, this.arguments);
}
}
}
被代理的对象
public class TargetSource {
private Class<?> targetClass;
private Class<?>[] interfaces;
private Object target;
}
AspectJAroundAdvice是通知的具体实现:增强逻辑的实现
AspectJExpressionPointcut是切点的具体实现:类过滤,方法匹配
AspectJExpressionPointcutAdvisor是切点通知器的具体实现:管理切点和通知
与容器整合AspectJAwareAdvisorAutoProxyCreator,在bean初始化的前后实现创建代理对象。
public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware {
private AbstractBeanFactory beanFactory;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
if (bean instanceof AspectJExpressionPointcutAdvisor) {
return bean;
}
if (bean instanceof MethodInterceptor) {
return bean;
}
List<AspectJExpressionPointcutAdvisor> advisors = beanFactory
.getBeansForType(AspectJExpressionPointcutAdvisor.class);
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
if (advisor.getPointcut().getClassFilter().matches(bean.getClass())) {
ProxyFactory advisedSupport = new ProxyFactory();
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
TargetSource targetSource = new TargetSource(bean, bean.getClass(), bean.getClass().getInterfaces());
advisedSupport.setTargetSource(targetSource);
return advisedSupport.getProxy();
}
}
return bean;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws Exception {
this.beanFactory = (AbstractBeanFactory) beanFactory;
}
}
调用顺序
测试
这个测试非常具有代表性
public class JdkDynamicAopProxyTest {
@Test
public void testInterceptor() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc.xml");
HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
helloWorldService.helloWorld();
//在AspectJAwareAdvisorAutoProxyCreator中已经对bean做了CGlib代理,所以获取的是代理对象,
//因为CGlib针对的是类,所以代理对象类型是HelloWorldServiceImpl
System.out.println("class =" + helloWorldService.getClass().getName());//us.codecraft.tinyioc.HelloWorldServiceImpl$$EnhancerByCGLIB$$635bc03b
System.out.println(helloWorldService instanceof Cglib2AopProxy);//false
System.out.println(helloWorldService instanceof JdkDynamicAopProxy);//false
System.out.println(helloWorldService instanceof HelloWorldService);//true
System.out.println(helloWorldService instanceof HelloWorldServiceImpl);//true
AdvisedSupport advisedSupport = new AdvisedSupport();
TargetSource targetSource = new TargetSource(helloWorldService, HelloWorldServiceImpl.class,HelloWorldService.class);
advisedSupport.setTargetSource(targetSource);
TimerInterceptor timerInterceptor = new TimerInterceptor();
advisedSupport.setMethodInterceptor(timerInterceptor);
JdkDynamicAopProxy jdkDynamicAopProxy = new JdkDynamicAopProxy(advisedSupport);
HelloWorldService helloWorldServiceProxy = (HelloWorldService) jdkDynamicAopProxy.getProxy();
helloWorldServiceProxy.helloWorld();
//上面已经使用了代理,而下面又创建了代理对象,而且是JDK实现的,
//因为重新new JdkDynamicAopProxy(),所以获取的是新的代理对象。又因为JDK是针对接口做代理的,所以判断代理的类型是HelloWorldService
System.out.println("class = = " + helloWorldServiceProxy.getClass().getName());//com.sun.proxy.$Proxy2
System.out.println(helloWorldServiceProxy instanceof Cglib2AopProxy);//false
System.out.println(helloWorldServiceProxy instanceof JdkDynamicAopProxy);//false
System.out.println(helloWorldServiceProxy instanceof HelloWorldService);//true
System.out.println(helloWorldServiceProxy instanceof HelloWorldServiceImpl);//false
}
}
tinyioc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<bean id="outputService" class="us.codecraft.tinyioc.OutputServiceImpl">
</bean>
<bean id="helloWorldService" class="us.codecraft.tinyioc.HelloWorldServiceImpl">
<property name="text" value="Hello World!"></property>
<property name="outputService" ref="outputService"></property>
</bean>
<bean id="autoProxyCreator" class="us.codecraft.tinyioc.aop.AspectJAwareAdvisorAutoProxyCreator"></bean>
<bean id="timeInterceptor" class="us.codecraft.tinyioc.aop.TimerInterceptor"></bean>
<bean id="aspectjAspect" class="us.codecraft.tinyioc.aop.AspectJExpressionPointcutAdvisor">
<property name="advice" ref="timeInterceptor"></property>
<property name="expression" value="execution(* us.codecraft.tinyioc.*.*(..))"></property>
</bean>
</beans>