一、什么叫做代理?
代理模式是JAVA设计模式中的一种,作用是创建一个与委托类实现同样的接口代理类,为委托类提供预处理消息、过滤消息、转发消息至委托类、以及处理结尾等功能。代理类与委托类是一对一的,并且代理类并不真正实现服务,而是通过将消息转发给委托类的相关方法来实现服务的提供。通俗易懂一点就是我们是通过调用代理对象来访问的实际对象,而代理对象可以在调用实际对象的前后或途中进行功能的扩展。
二、为什么要使用代理?
1、客户端可能无法直接操作对象(在另一台机器),那么可以在客户端建立一个代理对象,然后客户端直接调用目标对象,代理对象在与目标对象建立联系
2、需要加强目标对象的功能。有人表示为什么不在当初的类中加好,要使用代理来补充。单一职责要求一个类的功能尽可能单一,而且增强的功能大多都是与之前业务不同,比如增加日志输出,权限判断等,本来就不应该由之前的类去承担
三、代理的实现?
1、静态代理
是由程序员开发时写在源码中并在编译时就已经将接口、委托类、代理类等确定下来了,并且在程序运行之前,代理类的.class文件就已经生成。这类代理模式被称为静态代理。
1、确定接口
创建一个名为Person的父类,并设置一个名为sayHello的抽象方法
public interface Person {
public void sayHello();
}
2、委托类
创建一个名为Student的子类,并实现sayHello的方法
public class Student implements Person{
private String name;
public Student() {
}
public Student(String name) {
this.name = name;
}
@Override
public void sayHello() {
System.out.println(name + "到了");
}
}
3、代理类
创建一个名为StudentProxy的代理类并继承Person接口,实现sayHello的方法,设置有参构造,参数为被代理的委托类,并在sayHello方法中转发调用消息到对应的委托类中。
public class StudentProxy implements Person{
private Student student;
public StudentProxy(Student student) {
this.student = student;
}
@Override
public void sayHello() {
System.out.println("班长确认中:");
student.sayHello();
}
}
4、执行测试
public class StaticProxy {
public static void main(String[] args) {
Person proxy = new StudentProxy(new Student("张三"));
proxy.sayHello();
}
}
2、动态代理
代理类在程序运行时创建的代理方式被成为动态代理。
1、JDK动态代理
1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类 ,使用的是 Java反射技术实现,生成类的过程比较高效。
2、JDK代理是不需要第三方库支持,只需要JDK环境就可以进行代理,使用条件:实现InvocationHandler + 使用Proxy.newProxyInstance产生代理对象 + 被代理的对象必须要实现接口
// 实现InvocationHandler接口
public class JdkProxy<T> implements InvocationHandler {
private T target;
public JdkProxy(T t) {
this.target = t;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行代理了哦");
Object invoke = method.invoke(target, args);
System.out.println("代理执行完了哦");
return (T)invoke;
}
}
public class JdkProxyMain {
public static void main(String[] args) {
Person student = new Student("张三");
// 调用Proxy的newProxyInstance的方法获取到代理类
Person instance = (Person)Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), new JdkProxy<>(student));
instance.sayHello();
}
}
2、Cglib动态代理
1、CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 ,使用asm字节码框架实现,相关执行的过程比较高效,生成类的过程可以利用缓存弥补,因为是继承,所以该类或方法最好不要声明成final
2、CGLib必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类,覆盖其中的方法,是一种继承但是针对接口编程的环境下推荐使用JDK的代理;
// 实现MethodInterceptor接口
public class CglibProxy implements MethodInterceptor {
private Object target;
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// 增强代理方法
System.out.println("开始了哦");
Object invoke = method.invoke(target, objects);
System.out.println("结束了哦");
return invoke;
}
public Person getProxy(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
//设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类
enhancer.setSuperclass(target.getClass());
// 设置回调函数
enhancer.setCallback(this);
Object o = enhancer.create();
return (Person) o;
}
}
public class CglibProxyMain {
public static void main(String[] args) {
// 实例化CglibProxy对象
CglibProxy cglibProxy = new CglibProxy();
// 获取代理对象
Person person = cglibProxy.getProxy(new Student("张三"));
person.sayHello();
}
}
3、注意
在《精通Spring4.x 企业应用开发实战》给出建议:单例使用cglib,多例使用jdk
原因:jdk创建对象性能高于cglib,而生成对象的运行性能却比cglib低