概念
代理模式是常见的设计模式之一,顾名思义,代理模式就是代理对象具备真实对象的功能,并代替真实对象完成相应操作,并能够在操作执行的前后,对操作进行增强处理。(为真实对象提供代理,然后供其他对象通过代理访问真实对象)
一、静态代理
静态代理主要是通过继承接口,来对方法进行约束从而只在原有的方法基础上去增强,再通过创建实体类对象从而调用到原有的方法。
代码实现:
- 接口A(定义主要的方法)
public interface A {
void A();
}
- 实现类B(实现A接口中的方法)
public class B implements A{
@Override
public void A() {
System.out.println(“使用B实现A的方法”);
}
}
- 代理类AProxy(实现A接口对方法进行约束,调用实现类B的方法并对其进行增强)
public class AProxy implements A {
private A a;
public AProxy(A a) {
this.a = a;
}
@Override
public void A() {
System.out.println("代理类前置");
a.A();
System.out.println("代理类后置");
}
}
存在的问题:
- 不利于代码拓展,在接口中添加一个抽象方法时,所有的实现类都要重新实现否则报错。
- 代理对象需要创建很多,这种设计很不方便。
二、动态代理
概述
动态代理允许使用一种方法的单个类(代理类)为具有任意数量方法的任意类(真实类)的多个方法调用提供服务。
1.JDK动态代理
- Jdk代理涉及到java.lang.reflect包中的InvocationHandler接口和Proxy类,核心方法是
public Object invoke(Object proxy, Method method, Object[] args)
- jdk动态代理过程中实际上代理的是接口,是因为在创建代理实例的时候,依赖的是java.lang.reflect包中Proxy类的newProxyInstance方法
//(目标对象的类加载器,当前对象实现的所有接口,方法的拦截器)
A aprox = (A) Proxy.newProxyInstance(B.class.getClassLoader(), B.class.getInterfaces(), bHandler);
1.1具体代码实现:
- A接口定义需要实现的方法
public interface A {
void A();
void AB();
}
- 实现A接口的方法
public class B implements A{
@Override
public void A() {
System.out.println("A的方法实现!");
}
@Override
public void AB() {
System.out.println("AB方法的实现!");
}
}
- 定义代理类的拦截器并对方法名进行判断从而对指定的方法进行增强
public class BHandler implements InvocationHandler {
private Object a;
public BHandler(Object a) {
this.a = a;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object o=null;
//只针对AB进行代理
if("AB".equals(method.getName())){
System.out.println("方法前置通知!");
o=method.invoke(a,args);
System.out.println("方法后置通知!");
}else {
o=method.invoke(a,args);
}
return o;
}
}
- 测试类
public class Test {
public static void main(String[] args) {
A a=new B();
BHandler bHandler = new BHandler(a);
A aprox = (A) Proxy.newProxyInstance(B.class.getClassLoader(), B.class.getInterfaces(), bHandler);
aprox.A();
System.out.println("--------------------------------");
aprox.AB();
}
}
1.2与静态代理的对比
-
静态代理中,代理类和真实类实现的是同一个接口,重写同样的方法;jdk动态代理中,代理类和真实类关系不大,代理类实现无侵入式的代码扩展。
-
静态代理中当接口中方法增加的时候,在代理类代码量也会增加,显然是不妥的;jdk动态代理解决了这个问题,当业务增加,代理类的代码不会增加。
-
jdk动态代理实现的是jdk自带InvocationHandler接口,实现了这个接口的类也叫拦截器类,也叫代理类。
2.cglib动态代理
**从上面可以看出,jdk动态代理的前提条件是,要有接口存在,那还有许多场景是没有接口的,这个时候就需要cglib动态代理了,CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。
**
- A接口定义方法
public interface A {
void A();
void AB();
}
- B实现类实现A的方法
public class B implements A {
@Override
public void A() {
System.out.println("A的方法实现!");
}
@Override
public void AB() {
System.out.println("AB方法的实现!");
}
}
- 定义代理类的拦截器,不用像JDK动态代理一样将代理目标接口传入
public class BInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代理前置通知!");
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("代理后置通知!");
return o1;
}
}
- 测试(在测试的时候将目标类的父类传入通过继承的方式拿到方法)
public class Test {
public static void main(String[] args) {
//得到方法拦截器
BInterceptor bInterceptor = new BInterceptor();
//使用CGLIB框架生成目标的子类(代理类)实现方法增强
Enhancer enhancer = new Enhancer();
//设置父类字节码
enhancer.setSuperclass(B.class);
//设置代理处理
enhancer.setCallback(bInterceptor);
A a = (A) enhancer.create();
a.A();
}
}