项目搭建
为了更好地阐述AOP的原理,这里我们来实现一个简单地需求,计算除法。 下面的代码中分别创建了一个计算类和一个计算代理类,熟悉SpringAOP开发的读者应该非常熟悉下面的代码格式。
实现下面的代码需要添加依赖:
compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.9.5'
compile group: 'org.springframework', name: 'spring-context', version: '5.2.6.RELEASE'
定义 MathCalculator
用户被代理,实现一个整数的除法;定义 MathCalculatorAspect
用户实现AOP 代理,切入点 execution(public double com.zhoutao123.spring.aop.MathCalculator.*(..))
分别实现前置通知,后置通知,环绕通知以及异常通知(其他通知方式,读者可以自己实现测试)
// 定义目标代理类
public class MathCalculator {
public double div(Integer a, Integer b) {
System.out.println("调用业务代码");
return a * 1.0 / b;
}
}
// 定义代理类
@Aspect
public class MathCalculatorAspect {
@Pointcut("execution(public double com.zhoutao123.spring.aop.MathCalculator.*(..))")
public void pointCut() {
}
@Before("pointCut()")
public void before(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
System.out.println("Before 方法名称:" + signature.getName() + " 参数表:" + Arrays
.toString(joinPoint.getArgs()));
}
@After("pointCut()")
public void after() {
System.out.println("后置执行");
}
@AfterReturning(value = "pointCut()", returning = "result")
public void afterReturning(Object result) {
System.out.println("返回值:" + (result == null ? "null" : result.toString()));
}
@AfterThrowing(value = "pointCut()", throwing = "exception")
public void afterThrowing(Exception exception) {
System.out.println("异常信息:" + (exception == null ? "null" : exception.getMessage()));
}
}
同时需要创建一个配置类,用于启动Spring项目以及注入 MathCalculator
& MathCalculatorAspect
,执行main方法可以看到代理日志的输出
@Configurable
@EnableAspectJAutoProxy
public class MainConfigOfAOP {
@Bean
public MathCalculator matchCalculator() {
return new MathCalculator();
}
@Bean
public MathCalculatorAspect aspect() {
return new MathCalculatorAspect();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext
context = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
MathCalculator bean = context.getBean(MathCalculator.class);
bean.div(1, 0);
}
}
// 输出日志
Before 方法名称:div 参数表:[18, 3]
调用业务代码
后置执行
返回值:6.0
源码分析
细心地读者可能发现,在MainConfigOfAOP的类中,出现了一个注解 @EnableAspectJAutoProxy
这个注解使用常见的SPring提供的 @EnableXXXX
类型的注解,这个注解非常重要,使用@Import注解 导入需要的Bean类型对象。
@Configurable
@EnableAspectJAutoProxy
public class MainConfigOfAOP {}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {}
EnableAspectJAutoProxy 注解
如上文所示,EnableASpectJAutoProxy注解导入 @Import(AspectJAutoProxyRegistrar.class
而 AspectJAutoProxyRegistrar
是一个 ImportBeanDefinitionRegistrar
,ImportBeanDefinitionRegistrar 可以向IOC中注册BeanDefinition。AspectJAutoProxyRegistrar 会向Spring的容器中注入一个类型为 AnnotationAwareAspectJAutoProxyCreator
的BeanPostProcessor(后置处理器)用户处理Bean对象。
关于 ImportBeanDefinitionRegistrar 导入Bean的注册器 以及 BeanPostProcessor 后置处理器,在笔者的同栏文章,均有详细的阐述,对这里不太明白的,可以查阅这些文章或者留言!
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
// .....
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
AnnotationAwareAspectJAutoProxyCreator 是一个后置处理器,继承了 BeanPostProcessor
,AspectJAutoProxyRegistrar 想SpringIOC 注入这个Bean的定义之后,Sprin会在之后创建这个对象实例。
Spring容器启动
容器启动后AnnotationAwareAspectJAutoProxyCreator
被创建,并且被收到IOC 的后置处理器集合中,然后继续执行创建Bean,创建Bean的过程中获取遍历后置处理器,分别来进行处理这些Bean。
// 所在类 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 调用方法,判断是否需要封装(即是否需要被代理)
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// .......
// 获取增强点,如果增强点不存在,则不在创建代理,否则执行createProxy() 方法创建代理对象
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() 方法的核心类为 ProxyFactory
**
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
//....
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 获取增强点信息
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 封装到 ProxyFactory 中
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 模板方法,忽略
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 生成代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
众所周知,Spring生成代理对象有两种方式: JDK & Cglib, DefaultAopProxyFactory 的代码中提供了说明
@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.");
}
// 如果代理类是接口 或者 是一个代理类,则直接走JDK动态代理,否则走Cglib代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
JDK 方式实现动态代理
JDK的动态代理是通过实现 InvocationHandler实现了,然后重写invoke方法,这和我们之前的项目中使用JDK动态代理的方式是一致的。
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
// ...... 省略代码
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
// 获取目标方法的拦截链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 如果拦截链为空,则使用反射的方法执行,否则生成MethodInvocation,进行执行
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
Cglib 方式实现动态代理
Cglib 动态代理是基于字节码实现的,因此性能相对于JDK代理而言较高。一般情况下,Cglib的代理生成类如下所示:
// 定义拦截器
public class MyMethodInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("调用代理方法");
return proxy.invokeSuper(obj, args);
}
}
//创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数
Enhancer enhancer = new Enhancer();
//设置目标类的字节码文件
enhancer.setSuperclass(Cat.class);
//设置回调函数
enhancer.setCallback(new MyMethodInterceptor());
//这里的creat方法就是正式创建代理类
Cat proxyCat = (Cat)enhancer.create();
//调用代理类的eat方法
proxyCat.eat();
而在Sprint中使用CGlib实现代理的方式也是大同小异,具体分析如下:
@Override
public Object getProxy() {
return getProxy(null);
}
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}
try {
// 获取代理目标类
Class<?> rootClass = this.advised.getTargetClass();
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// 设置Cglib代理的目标类等配置信息
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
// 生成回调方法
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// 直接生成代理类,并返回实例对象
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
enhancer.setInterceptDuringConstruction(false);
enhancer.setCallbacks(callbacks);
return (this.constructorArgs != null && this.constructorArgTypes != null ?
enhancer.create(this.constructorArgTypes, this.constructorArgs) :
enhancer.create());
}