代理模式有动态代理和静态代理:静态代理模式中代理类是自己已经定理好的,在程序运行前就已经编译好了,然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。*相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法*。 比如说,想要在每个代理的方法前都加上一个处理方法:
JDK动态代理只能对实现了接口的类生成代理,而不能针对类,使用的是Java反射技术实现,不需要第三方库的支持,生成比较高效。
CGLIB主要是针对一个类生成子类,覆盖其中的方法,是一种继承,并且需要第三方库asm字节码框架来支持。
1.确定创建接口具体行为
/**
* 确定具体得行为接口
* */
public interface Person {
// 上交班费
void giveMoney();
2.被代理对象 Student 实现接口,实现接口的具体行为的方法。
/**
* 被代理类
*/
public class Student implements Person{
@Override
public void giveMoney() {
System.out.println("学生上交班费....");
}
}
3.代理对象,因为代理对象需要去代理被代理对象,所以代理对象必须同样实现被代理对象类的接口。代理对象需要完成委托类预处理消息,消息过滤、转发,所以他必须得持有一个被代理对象,可以是继承或者是关联。
/**
* 学生的代理类 实现消息的委托、转发
*/
public class StudentsProxy implements Person{
// 消息的委托必须要交给被代理类,所以得关联一个被代理类
private Student student;
// 只会代理学生类
public StudentsProxy(Person student){
if (student.getClass() == Student.class){
this.student = (Student) student;
}
}
// 代替上交班费 调用被代理学生得上交班费行为
@Override
public void giveMoney() {
// 代理类增加其他前置逻辑
System.out.println("由我给你张三代缴班费吧。。。。。");
student.giveMoney();
}
}
4.测试
public class ProxyTest {
public static void main(String[] args) {
// 创建被代理类
Student zhangSan = new Student();
// 创建代理类并且代理张三上交班费
Person studentsProxy = new StudentsProxy(zhangSan);
// 这样上缴班费就交给了学生得代理类了 用户无感知,只知道由谁能够给我实现上交班费功能即可。
studentsProxy.giveMoney();
}
}
1.确定创建接口得具体行为
/**
* 确定具体得行为接口
* */
public interface Person {
// 上交班费
void giveMoney();
}
2.确定被代理对象实现接口,并且完成具体业务逻辑
/**
* 被代理类
*/
public class Student implements Person {
@Override
public void giveMoney() {
System.out.println("学生上交班费....");
}
}
3.自定义一个InvocationHandler类,并且实现InvocationHandler接口,这个类种会持有一个被代理对象target,并且InvocationHandler中有一个invoke方法,所有执行代理对象得方法都会被替换成执行invoke方法
/**
* @Author Tang
**/
public class StudentInvocationHandler<T> implements InvocationHandler {
// 持有一个被代理对象
T target;
// 定义一个构造器
public StudentInvocationHandler(T target) {
this.target = target;
}
/**
* proxy:代表动态代理对象
* method 代表正在执行得方法
* args:代表调用目标方法时传入的实参
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行方法....");
method.invoke(target, args);
System.out.println("执行结束,结果为:");
return "执行成功....";
}
}
4.测试
public class ProxyTest {
public static void main(String[] args) {
// 生成一个被代理类
Person student = new Student();
StudentInvocationHandler<Person> studentInvocationHandler = new StudentInvocationHandler(student);
// 使用Proxy得静态方法创建代理类
// 第一个参数是我们被代理的对象 也可以写成它实现的接口
// 第二个 interface对象数组 表明代理类实现了这些接口 那么代理类就可以调用接口中声明的所有方法。
// 第三个 表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上
Person personProxy=(Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, studentInvocationHandler);
//使用动态代理类来
personProxy.giveMoney();
}
}
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
这个方法的作用就是创建一个代理类对象,它接收三个参数,我们来看下几个参数的含义:
loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。