作为面向对象(OOP)的补充,切面编程(AOP)在纵向(方法增强)进一步降低了代码冗余,提高了开发效率。但我知道怎么回事,却总是不能深刻的理解。于是原理与代码结合学习,记录下来。
1 实现原理
AOP的主要作用就是通过不修改源代码的方式,将非核心功能的代码组织入来实现对方法的增强。实现的关键在于使用了代理模式。代理模式的作用就是为其他代码提供一种代理,以控制对这个对象的访问。用于解决直接访问对象时带来的各种问题。代理的方式分为两种:静态代理和动态代理。
1.1 静态代理
静态代理主要通过目标类与代理类实现同一个接口。让代理类持有真实对象,然后在代理类方法中调用真实类方法。在代理类方法前后添加我们所需要的功能扩展代码来达到增强的目的。相关代码如下:
// 目标接口
public interface Subject {
void request();
void response();
}
// 目标类
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("执行目标对象request方法");
}
@Override
public void response() {
System.out.println("执行目标对象response方法");
}
}
// 代理类
public class ProxySubject implements Subject {
private Subject subject;
/**
* 构造方法
* @param subject
*/
public ProxySubject(Subject subject) {
this.subject = subject;
}
@Override
public void request() {
System.out.println("前置增强");
subject.request();
System.out.println("后置增强");
}
@Override
public void response() {
System.out.println("前置增强");
subject.response();
System.out.println("后置增强");
}
}
// 函数入口
public static void main(String[] args) {
// 代理对象 通过构造器注入目标对象
Subject subject = new RealSubject();
ProxySubject proxySubject = new ProxySubject(subject);
// 增强实现
proxySubject.request();
// 增强实现
proxySubject.response();
}
1.2 动态代理
1.2.1 JDK动态代理
JDK动态代理与静态代理一样,目标类需要实现一个代理接口,开发步骤如下:
步骤一: 定义一个java.lang.reflect.InvocationHandler接口的实现类,重写invoke方法。
步骤二: 将InvocationHandler对象作为参数传入java.lang.reflect.Proxy的newProxyInstance方法中。
步骤三: 通过调用java.lang.reflect.Proxy的newProxyInstance方法获得动态代理对象。
步骤四: 通过代理对象调用目标方法。
相关代码如下:
public class JdkProxySubject implements InvocationHandler {
// 之前静态代理的类
private Subject subject;
/**
* 构造方法
* @param subject
*/
public JdkProxySubject(Subject subject) {
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before 前置通知");
Object result = null;
try {
result = method.invoke(subject, args);
}catch (Exception ex) {
System.out.println("ex: " + ex.getMessage());
throw ex;
}finally {
System.out.println("after 后置通知");
}
return result;
}
}
// 程序入口
public static void main(String[] args) {
//获取InvocationHandler对象 在构造方法中注入目标对象
//获取代理类对象
InvocationHandler handler = new JdkProxySubject(new RealSubject());
//调用目标方法
Subject proxySubject = (Subject) Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[]{Subject.class},
handler);
proxySubject.request();
proxySubject.response();
}
1.2.2 CgLib动态代理
CgLib动态代理的原理是对指定的业务类生成一个子类,并覆盖其中的业务方法来实现代理。开发步骤如下:
步骤一: 定义一个org.springframework.cglib.proxy.MethodInterceptor(在spring-core包中)接口的实现类,重写intercept方法。
步骤二: 获取org.springframework.cglib.proxy.Enhancer类的对象。
步骤三: 分别调用Enhancer对象的setSuperclass和setCallback方法,使用create方法获取代理对象。
步骤四: 通过代理对象调用目标方法。
相关代码如下所示:
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before 前置通知");
Object result = null; try {
result = methodProxy.invokeSuper(o, objects);
}catch (Exception ex) {
System.out.println("ex: " + ex.getMessage());
throw ex;
}finally {
System.out.println("after 后置通知");
}
return result;
}
}
// 程序入口
public static void main(String[] args) {
//获取Enhancer 对象
Enhancer enhancer = new Enhancer();
//设置代理类的父类(目标类)
enhancer.setSuperclass(RealSubject.class);
//设置回调方法
enhancer.setCallback(new MyMethodInterceptor());
//获取代理对象
Subject proxySubject = (Subject)enhancer.create();
//调用目标方法
proxySubject.request();
proxySubject.response();
}