一、AOP是什么?
Aspect Oriented Programming(AOP) 面向切面编程。
名称 | 解释 |
---|---|
静态代理 | 一个代理接口只能服务于一种类型的对象 |
动态代理 | 不必为特定对象与方法编写特定的代理对象,使用动态代理,可以使得一个处理者(Handler)服务于各个对象. |
静态代理例子
//接口
public interface AInterface {
void hi();
}
//实现
public class A implements AInterface {
@Override
public void hi() {
System.out.println("hi");
}
}
//代理类
public class AProxy implements AInterface {
private AInterface a= new A();
@Override
public void hi() {
System.out.println("Before invoke hi" );
a.hi();
System.out.println("After invoke hi");
}
}
//代理调用
public static void main(String[] args) {
AProxy aProxy = new AProxy();
aProxy .hi();
}
输出:
Before invoke hi
hi
After invoke hi
动态代理例子
1 jdk proxy
- 定义一个
InvocationHandler
实例,它负责实现接口的方法调用; - 通过
Proxy.newProxyInstance()
创建interface
实例,它需要3个参数:- 使用的
ClassLoader
,通常就是接口类的ClassLoader
; - 需要实现的接口数组,至少需要传入一个接口进去;
- 用来处理接口方法调用的
InvocationHandler
实例。
- 使用的
- 将返回的
Object
强制转型为接口。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//接口
interface Hello {
void morning(String name);
}
//调用
public class Main {
public static void main(String[] args) {
//创建了一个Hello接口对象
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method);
if (method.getName().equals("morning")) {
System.out.println("Good morning, " + args[0]);
}
return null;
}
};
Hello hello = (Hello) Proxy.newProxyInstance(
Hello.class.getClassLoader(), // 传入ClassLoader
new Class[] { Hello.class }, // 传入要实现的接口
handler); // 传入处理调用方法的InvocationHandler
hello.morning("Bob");
}
}
//动态代理实际上是JDK在运行期动态创建class字节码并加载的过程,它并没有什么黑魔法,把上面的动态代理改写为静态实现类大概长这样:
public class HelloDynamicProxy implements Hello {
InvocationHandler handler;
public HelloDynamicProxy(InvocationHandler handler) {
this.handler = handler;
}
public void morning(String name) {
handler.invoke(
this,
Hello.class.getMethod("morning"),
new Object[] { name });
}
}
2 cglib proxy
使用cglib实现动态代理,并不要求委托类必须实现接口,底层采用asm字节码生成框架生成代理类的字节码
package cglib;
//实现类
public class Hello {
public void morning() {
System.out.println("morning");
}
}
//代理类
public class CglibTs implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 设置回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
/**
* 实现MethodInterceptor接口中重写的方法
*/
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("事务开始。。。");
Object result = proxy.invokeSuper(object, args);
System.out.println("事务结束。。。");
return result;
}
}
//测试类
public class MainTest {
public static void main(String[] args) {
CglibTs ct = new CglibTs();
Hello hello= (Hello) ct.getProxy(Hello.class);
hello.morning()
}
}
//结果
事务开始。。。
morning
事务结束。。
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。 CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。 因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。
二、Spring AOP如何实现的?
Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:
1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB
实现方式
- xml配置AOP
spring-aop.xml 中,配置pointcut .编写实际的aspect 类 业务处理
- 注解配置AOP
1 @Component 注解把AopConfig 加入到IOC容器中 ,2使用 @Aspect
三、使用场景
日志记录,性能统计,安全控制,事务处理,异常处理
具体场景就是:将后台管理系统中的 操作日志写入到数据库记录,
- 自定义一个注解类
- 编写切面类 Pointcut到注解上 ,记录操作日志到数据库
- 将注解类配置到你要控制的方法
参考:
SpringAOP原理分析
Spring Boot实践——AOP实现
Spring Boot Aop
Spring AOP实现原理