AOP(面向切面编程)的本质就是Spring的动态代理开发,通过代理类为原始类增加额外功能。
文章目录AOP原理分析
AOP的开发方式JDK动态代理CGLIB动态代理AOP的坑
AOP的开发方式MethodInterceptor
MethodInterceptor方法拦截器接口---->实现类–>invoke方法(书写额外功能)
参数:MethodInvocation: 额外功能所增加给的原始方法
//object为原始方法的返回值
public Object invoke(MethodInvocation invocation)throws Throwable{
//前置额外方法(befor)
----
Object ret = invocation.proceed(); //目标(原始)方法运行
----
//后置额外方法
return ret;
}
@Aspect
@Order(0) //优先级
@Aspect //切面类
@Component
public class DatabaseAop {
@Around("@annotation(database)") //切入点
public Object setWrite(ProceedingJoinPoint joinPoint, Database database) throws Throwable {
DbContextHolder.setDbType(database.databaseName());
return joinPoint.proceed(); //原始方法运行
}
}
JDK动态代理AOP如何创建动态代理类(动态字节码技术)
代码实例:
public void TestProxy(){
//1.创建原始方法
ApiOaService apiOaService = new ApiOaServiceImpl();
//2.JDK创建动态代理
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("--------log-----------");
//1.原始方法运行
Object ret = method.invoke(apiOaService, args);
//2.添加额外功能
System.out.println("----------log----------");
return ret;
}
};
ApiOaService proxyApiOAService = (ApiOaService) Proxy.newProxyInstance(apiOaService.getClass().getClassLoader(), apiOaService.getClass().getInterfaces(), handler);
//调用被代理的方法
proxyApiOAService.applyOA();
}
图解分析:
代理类和原始类实现相同接口的原因:
CGLIB动态代理如果目标类(原始类)没有实现接口,这时候JDK的方法就无法创建动态代理。CGLIB会已继承的方式创建动态代理。
CGLIB创建动态代理的原理:父子继承关系创建代理对象,原始类作为父类,代理类作为子类,这样既可以保证2者方法一致,同时在代理中提供新的实现。
代码实例:
public void CglibTestProxy(){
//1.原始对象
WechatServiceImpl wechatService = new WechatServiceImpl();
//2.通过cglib创建代理对象
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(wechatService.getClass().getClassLoader());
enhancer.setSuperclass(wechatService.getClass());
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("-----------log------------");
Object ret = method.invoke(wechatService, args); //原始方法运行
System.out.println("-----------log------------");
return ret;
}
});
WechatServiceImpl proxy = (WechatServiceImpl) enhancer.create();
proxy.getAccessToken();
}
总结
- 1.JDK实现动态代理 Proxy.newProxyInstance(); //通过接口创建动态代理 - 2.CGLIB实现动态代理 Enhancer //通过父子继承的方式创建动态代理
底层默认是JDK的方式,如果需要切换CGlib
@EnableAspectJAutoProxy(proxyTargetClass = true)
Spring工厂如何加工创建代理对象
BeanPostProcessorAOP的坑
同一个service中,不同方法之间会有调用的情况。
举个栗子:
首先创建一个切面类
@Aspect
@Component
public class TestAop {
@Around("@annotation(Log)")
public Object setLog(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("======log=======");
Object ret = joinPoint.proceed();
System.out.println("=======log======");
return ret;
}
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Log {
}
正常情况:
不同方法间调用的情况:
可以发现,a并没有调用b的代理方法,而是调用了原始方法。
如何才能获取到代理对象呢??
这里提供两种解决方案:
启用类加入 @EnableAspectJAutoProxy(exposeProxy = true)
从ApplicationContext获取当前Service对象
- 1.实现 ApplicationContextAware接口 - 2. 重写setApplicationConetext方法获取工厂 - 3. 用工厂的getBean()方法创建对象,创建的对象几位代理对象。



