代理模式是23种设计模式种的一种。代理模式是一种结构型设计模式,它允许为其他对象提供一个替代品或占位符,以控制对这个对象的访问。代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。
适配器模式一般包含三种角色:
代理模式主要有三种形式,分别是静态代理、动态代理(也称JDK代理、接口代理)和CGLIB代理(在内存动态创建对象而不需要实现接口,也可属于动态代理得范畴)
静态代理是定义父类或者接口,然后被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类。代理对象与目标对象实现相同的接口,然后通过调用相同的方法来调用目标对象的方法。
public interface Animal {
void eat();
}
public class Dog implements Animal {
@Override
public void eat() {
System.out.println("吃吃吃");
}
}
public class DogProxy implements Animal {
private Animal target; //通过接口聚合目标对象
public DogProxy(Animal target) {
this.target = target;
}
@Override
public void eat() {
System.out.println("静态代理开始");
target.eat();
System.out.println("静态代理结束");
}
}
public class Main {
public static void main(String[] args) {
//创建被代理对象
Dog dog = new Dog();
//创建代理对象, 同时将被代理对象传递给代理对象
DogProxy dogProxy = new DogProxy(dog);
//通过代理对象,调用到被代理对象的方法
dogProxy.eat();
}
}
动态代理是在运行时动态生成代理类,不需要手动编写代理类。Java种的动态代理主要是使用java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler接口实现。
优点:灵活性高、减少重复代码、统一处理逻辑、可以代理多个真实类。
缺点:基于反射机制,性能较低,且无法代理final类和方法。
动态代理最主要的就是Proxy.newProxyInstance方法,它是用于创建动态代理对象的静态方法。它接受三个参数:
ClassLoader:用于加载动态代理类的类加载器。
interfaces:要代理的接口数组。
InvocationHandler:实现了InvocationHandler接口的对象,用于处理代理对象的方法调用。
public interface Animal {
void eat();
}
public class Dog implements Animal {
@Override
public void eat() {
System.out.println("吃吃吃");
}
}
public class AnimalInvocationHandler implements InvocationHandler {
private Object target;
public AnimalInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("吃前加热");
Object result = method.invoke(target, args);
System.out.println("吃后清理");
return result;
}
}
public class AnimalProxy {
public static Animal createProxy(Animal animal) {
return (Animal) Proxy.newProxyInstance(
animal.getClass().getClassLoader(),
animal.getClass().getInterfaces(),
new AnimalInvocationHandler(animal));
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
Animal dogProxy = AnimalProxy.createProxy(dog);
dogProxy.eat();
}
}
JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类。
为了解决这个问题,我们可以用 CGLIB 动态代理机制来避免。
CGLIB代理也叫作子类代理,它使目标对象不需要实现接口,是在内存中构建一个子类对象从而实现对目标对象功能扩展,有的也将CGLIB代理归属到动态代理。
CGLIB是一个高性能的代码生成包,它可以在运行期扩展java类与实现java接口。被许多AOP的框架使用(如Spring AOP)。Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类。
public class Dog {
public void eat() {
System.out.println("吃吃吃");
}
}
public class AnimalMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("吃前加热");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("吃后清理");
return result;
}
}
public class DogCglibProxy {
public static Dog createProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Dog.class);
enhancer.setCallback(new AnimalMethodInterceptor());
return (Dog) enhancer.create();
}
}
public class Main {
public static void main(String[] args) {
Dog dogProxy = DogCglibProxy.createProxy();
dogProxy.eat();
}
}
CGLIB与java动态代理的区别
java.lang.reflect.Proxy
和InvocationHandler
接口。Java动态代理只能为接口创建代理对象,它是基于接口的代理。通过Proxy.newProxyInstance()
方法可以动态地生成实现了指定接口的代理类。InvocationHandler
的invoke
方法,再由invoke
方法调用实际的目标方法。这一层额外的调用可能会引入一些性能开销。Proxy.newProxyInstance()
方法动态生成代理对象,需要提供一个实现InvocationHandler
接口的对象。InvocationHandler
。CGLIB通过继承目标类并重写其中的方法来实现代理逻辑。代理模式可以在多种场景下使用,包括但不限于以下几个方面:
代理模式可以在多种场景下使用,包括但不限于以下几个方面: