一、AOP是什么?
面向切面编程,作为面向对象的一种补充,将公共逻辑(事务管理、日志、缓存等)封装成切面,跟业务代码进行分离,可以减少系统的重复代码和降低模块之间的耦合度。切面就是那些与业务无关,但所有业务模块都会调用的公共逻辑。
二、Spring AOP简易使用(注解版)
1、定义一个切面类Aspect
即在声明的类上,增加@Aspect、@Component两个注解,在配置类上添加@EnableAspectJAutoProxy注解开启AOP。(Spring是需要手动添加@EnableAspectJAutoProxy注解进行集成的,而SpringBoot中使用自动装配的技术,可以不手动加这个注解就实现集成。)
切面类:
@Aspect
@Component
public class LklAspect {
}
配置类:
@ComponentScan("com.lkl")
@EnableAspectJAutoProxy
public class ContextConfig {
}
2、定义切点Pointcut
定义切点,并定义切点在那些地方执行,采用@Pointcut注解完成,如@Pointcut(public * com.xxx.xxx.* . **(…))。规则:修饰符(可以不写,但不能用 * )+返回类型+哪些包下的类+哪些方法+方法参数 *代表所有,"…"两个点代表参数不限。
自定义注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
String value() default "";
}
切点方法:
@Aspect
@Component
public class LklAspect {
/**
* 这里演示注解的形式 匹配带有指定注解的连接点
* 当然,也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method
* 切点表达式: execution(...)
*/
@Pointcut("@annotation(com.lkl.aspect.anno.SysLog)")
public void myPointcut() {}
}
3、定义Advice通知
利用通知的5种注解@Before、@After、@AfterReturning、@AfterThrowing、@Around来完成在某些切点的增强动作,如@Before(“myPointcut()”),myPointcut为第二步定义的切点
代码如下:
@Aspect
@Component
public class LklAspect {
@Before("execution(* com.lkl.service.*.create*(..))")
public void before(JoinPoint joinPoint) {
System.out.println("准备执行方法: " + joinPoint.getSignature().getName() + ", 参数列表:" + Arrays.toString(joinPoint.getArgs()));
}
@AfterReturning(value = "execution(* com.lkl.service.*.query*(..))", returning = "returnValue")
public void afterReturning(JoinPoint point, Object returnValue) {
System.out.println(point.getSignature().getName() + "方法返回:" + returnValue);
}
}
三、AOP实现原理介绍
Spring AOP是通过动态代理实现的,代理模式,接口 + 真实实现类 + 代理类
,其中 真实实现类
和 代理类
都要实现接口,实例化的时候要使用代理类。所以,Spring AOP 需要做的是生成这么一个代理类,然后替换掉真实实现类来对外提供服务。
替换的过程怎么理解呢?在 Spring IOC 容器中非常容易实现,就是在 getBean(…) 的时候返回的实际上是代理类的实例,而这个代理类我们自己没写代码,它是 Spring 采用 JDK Proxy 或 CGLIB 动态生成的。
getBean(…) 方法用于查找或实例化容器中的 bean,这也是为什么 Spring AOP 只能作用于 Spring 容器中的 bean 的原因,对于不是使用 IOC 容器管理的对象,Spring AOP 是无能为力的。
Aspect概念
Spring AOP 中主要概念理解:
- aspect:切面,切面由切点和通知组成,即包括横切逻辑的定义也包括连接点的定义
- pointcut:切点,每个类都拥有多个连接点,可以理解是连接点得集合
- joinpoint:连接点,程序执行的某个特定位置,如某个方法调用前后等
- weaving:织入,将增强添加到目标类的具体连接点的过程
- advice:通知,是织入到目标类连接点上的一段代码,就是增强到什么地方?增强到什么内容?(五种通知类型)
- target:目标对象,通知织入的目标类
- aop Proxy:代理对象,即增强后产生的对象
JDK代理与CGLIB代理的区别
- JDK动态代理实现接口,CGLIB动态继承思想
- JDK动态代理(目标对象存在接口时)执行效率高于CGLIB
- 如果对象有接口实现,选择JDK代理,如果没有接口实现选择CGLIB代理
JDK、CGLIB代码简易实现:
- JDK动态代理:
接口:
public interface Subject {
void doSomething();
}
真实实现类:
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject do something");
}
}
代理类:
public class JDKDynamicProxy implements InvocationHandler {
private Object target;
public JDKDynamicProxy(Object target) {
this.target = target;
}
/**
* 获取被代理接口实例对象(代理对象)
*/
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Do something before");
Object result = method.invoke(target, args);
System.out.println("Do something after");
return result;
}
}
测试:
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
realSubject.doSomething();
System.out.println("***********************");
// jdk动态代理测试
Subject subject = new JDKDynamicProxy(new RealSubject()).getProxy();
subject.doSomething();
}
}
结果如下:
可以发现真实对象,运行还是原本的方法,使用动态代理生成的代理对象,则是增强后的方法。
- CGLIB动态代理:
父类:
public class RealSubject {
public void doSomething() {
System.out.println("RealSubject do something");
}
}
代理类:
public class CgLibProxy implements MethodInterceptor {
Object target;
public CgLibProxy(Object target) {
this.target = target;
}
/**
* 创建代理对象
*/
public Object getProxy() {
//可以通过Enhancer对象中的create()方法可以去生成一个类,用于生成代理对象
Enhancer enhancer = new Enhancer();
//设置父类(将目标类作为代理类的父类)
enhancer.setSuperclass(target.getClass());
//设置拦截器(回调对象为本身对象)
enhancer.setCallback(this);
//生成一个代理类对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("方法执行前的增强行为");
Object result = method.invoke(target, objects);
System.out.println("方法执行后的增强行为");
return result;
}
}
测试:
public class Test {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
realSubject.doSomething();
System.out.println("***********************");
RealSubject proxy = (RealSubject) new CgLibProxy(new RealSubject()).getProxy();
proxy.doSomething();
}
}
结果:
四、AOP入口(源码解析)
- spring集成AspectJ AOP主要是@EnableAspectJAutoProxy注解的作用。
该注解是一个复合注解,如下所示:
@Import注解可以注入一个类到Spring容器当中,上述注解将AspectJAutoProxyRegistrar类注入到spring容器里。spring容器初始化时,执行加载和注册beanDefinition的时候,会使用该类的registerBeanDefinitions方法进行注册beanDefinition。也就来到了AspectJAutoProxyRegistrar中的registerBeanDefinitions方法。
该方法的作用就是将AnnotationAwareAspectJAutoProxyCreator注册到容器当中,这个类是Spring AOP的关键。此时Spring中就有了Aspect AOP的功能
- 然后真正创建bean的方法
doCreateBean(...)
部分核心代码
// 创建实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
....
// 依赖注入,主要为属性的依赖注入
populateBean(beanName, mbd, instanceWrapper);
// 1、bean执行Aware回调方法 2、执行 beanPostProcessor前置方法
// 3、执行类的初始化方法 4、执行beanPostProcessor后置方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
- initializeBean(beanName, exposedObject, mbd)初始化bean
// BeanPostProcessors 前置方法的调用
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 调用类的初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
// bean 后置方法调用,在这里有可能对bean进行代理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
- 后置处理
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
- 动态代理入口
方法如下,判断是否需要代理
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 先从缓存中获取
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
//如果需要对该bean对象进行代理,返回代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
wrapIfNecessary(bean, beanName, cacheKey)
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//判断是否已经被代理
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
//不需要代理,或者配置了conditional跳过
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;
}
// Create proxy if we have advice.
//寻找切面
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;
}
- 创建代理对象 Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (proxyFactory.isProxyTargetClass()) {
// Explicit handling of JDK proxy targets (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass)) {
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// No proxyTargetClass flag enforced, let's apply our default checks...
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//获取代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
- 最后调用方法,根据不同类型调用不同动态代理模式获取代理对象