代理模式
代理模式: 为其他对象提供一种代理以控制这个对象的访问
- 用大白话来解释就是 ->
代理是给对象的方法做改进的
- 一个对象的方法并不完美,代理就是来给这个不完美的方法做改进的
- 比如调用方法之前做验证丶过滤等
- Java Spring的AOP就是标准的代理
- 可以在执行一个方法的前面或后面添加其他业务逻辑,来改进这个方法
静态代理
静态代理的特点
- 就是角色固定,修改角色和增加角色代理都比较费劲
一个接口,一个主类(实现接口),一个代理类(实现接口)
-
接口
//接口 interface Subject { //接口方法 public void request(); }
-
主类(实现接口)
//主类 class SubjectClass implements Subject { @Override public void request() { //业务处理逻辑 } }
-
代理类(实现接口)
//代理类 class SubjectProxy implements Subject { private Subject subject = null; public SubjectProxy() { //主类 this.subject = new SubjectClass(); } //代理业务方法 @Override public void request() { //代理前操作 this.subject.request(); //代理后操作 } }
-
main方法
//main方法 public static void main(String[] args) { Subject proxy = new SubjectProxy(); proxy.request(); }
动态代理
- 创建代理对象上更加的灵活,动态代理类的字节码在
程序运行
时,由 Java反射机制
动态产生。 - 它会根据需要,通过反射机制在程序运行期,动态的为目标对象创建代理对象,无需程序员手动编写它的源代码。
动态代理的两种实现方式:
- JDK 动态代理
- CGLIB动态代理
动态代理的特点
- 目标对象不固定,在应用程序执行时动态创建目标对象
JDK动态代理 -> 注:JDK动态代理的目标对象必须有接口实现
一个接口,一个接口实现类,一个实现特定接口的代理类
-
一个接口,一个接口实现类 -> 就跟静态代理一样,一个接口一个实现类
/** * jdk动态aop代理需要实现的接口 */ interface JdkInterface { public void add(); } /** * 被代理的类,即目标类target */ class JdkClass implements JdkInterface { @Override public void add() { System.out.println("目标类的add方法"); } }
-
实现
InvocationHandler接口
的代理类 -> 一个实现特定接口的代理类- 与静态代理是非常相似的,就是不在实现我们写的 接口而是特定的接口
/** * 这里加入切面逻辑 */ class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before-------切面加入逻辑"); Object invoke = method.invoke(target, args);//通过反射执行,目标类的方法 System.out.println("after-------切面加入逻辑"); return invoke; } }
-
main方法
public static void main(String[] args) { JdkClass jdkClass = new JdkClass(); MyInvocationHandler handler = new MyInvocationHandler(jdkClass); // Proxy为InvocationHandler实现类动态创建一个 符合某一接口的代理实例 //这里的proxyInstance就是我们目标类的增强代理类 JdkInterface proxyInstance = (JdkInterface) Proxy.newProxyInstance( jdkClass.getClass().getClassLoader(), jdkClass.getClass().getInterfaces(), handler ); proxyInstance.add(); //打印增强过的类类型 System.out.println("=============" + proxyInstance.getClass()); }
CGLIB动态代理实现AOP拦截 -> cglib不需要定义接口
一个主类,一个实现特定接口的代理类
-
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
-
主类
/** * 主类 */ class Base { public void add() { System.out.println("目标类的add方法"); } }
-
实现特殊接口的代理类
/** * 这里加入切面逻辑 */ class CglibProxy implements MethodInterceptor { @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before-------切面加入逻辑"); methodProxy.invokeSuper(object, args); System.out.println("after-------切面加入逻辑"); return null; } }
-
main方法
public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); //类增强器 生成动态子类以启用方法拦截。 Enhancer enhancer = new Enhancer(); //设置生成的类将扩展的类 -> 主类 enhancer.setSuperclass(Base.class); //设置实现了CGLIB的代理类 enhancer.setCallback(proxy); //此刻,base是增强过的目标类 Base base = (Base) enhancer.create(); base.add(); }
-
CGLIB是通过继承的方式做的动态代理 -> 类增强器
- 怎么理解呢?
/**
* 主类
*/
class Base {
public void add() {
System.out.println("目标类的add方法");
}
public void add2() {
System.out.println("目标类的add方法");
}
}
/**
* 这里加入切面逻辑
*/
class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("before-------切面加入逻辑");
methodProxy.invokeSuper(object, args);
System.out.println("after-------切面加入逻辑");
return null;
}
}
//------------------------最后生成的代理类会变成类似这样-------------------------------
class Proxy extends Base{
private Base base;
@Override
public void add() {
System.out.println("before-------切面加入逻辑");
base.add();
System.out.println("after-------切面加入逻辑");
}
@Override
public void add2() {
System.out.println("before-------切面加入逻辑");
base.add2();
System.out.println("after-------切面加入逻辑");
}
}
//
main(){
//此刻,base是增强过的目标类
//因为是继承过的,所以多态的缘故base.add()就是调用的代理类的add()
Base base = (Base) enhancer.create();
base.add();
}
如果被我代理的类有接口就用JDK代理,如果没有接口就用CGLIB代理
- AOP切的
对象有接口
,且方法是实现接口的方法
就用JDK代理 - 否则用CGLIB代理