代理模式是Java常见的设计模式之一。 所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。
在java中,代理模式主要分为静态代理与动态代理两大类,其主要的去别就是静态代理的代理对象是在项目运行之前就已经写好了的,可以在项目代码中直接看到:而动态代理是只有在项目跑起来之后,才厚产生的一个代理类,并不会在代码中直接体现出来。
1.静态代理
我们首先创建一个接口,StudentService
/**
* 学生服务接口
*/
public interface StudentService {
void study();
void play();
}
然后我们实现这个接口,这个接口便是真正要被代理的类
/**
* 学生服务实现类
*/
public class StudentServiceImpl implements StudentService {
@Override
public void study() {
System.out.println("学生爱学习");
}
@Override
public void play() {
System.out.println("学生爱玩耍");
}
}
之后我们来创建学生服务的代理类,同样实现学生服务这个接口,并且注入一个上面的实现类
/**
* 学生服务代理类
*/
@Component
public class StudentServiceProxy implements StudentService{
@Autowired
private StudentServiceImpl studentService;
@Override
public void study() {
System.out.println("扩展学习1");
studentService.study();
System.out.println("扩展学习2");
}
@Override
public void play() {
System.out.println("扩展玩耍1");
studentService.play();
System.out.println("扩展玩耍2");
}
}
之后我们调用这个代理类,我们并不知道原先的学生服务类的具体时间先,但却可以使用,增强学生服务类的功能,这就是静态代理的实现
2.动态代理
动态代理在java中分为jdk提供的动态代理,以及cglib实现的动态代理,这两者的区别是jdk提供的动态代理要求被代理者必须要提供一个接口,而cglib的动态代理需要被代理者提供一个类
2.1.jdk动态代理
我们同样使用上面的学生服务接口来说明
/**
* 学生服务接口
*/
public interface StudentService {
void study();
void play();
}
要被代理的实际对象
/**
* 学生服务实现类
*/
public class StudentServiceImpl implements StudentService {
@Override
public void study() {
System.out.println("学生爱学习");
}
@Override
public void play() {
System.out.println("学生爱玩耍");
}
}
调用处理器实现类,对目标类进行增强
/**
* 调用处理器实现类
* ,每次生成动态代理对象都需要指定一个实现了改接口的调用处理器对象
*/
public class InvocationHandlerImpl implements InvocationHandler {
/**
* 要代理的真实对象
*/
private StudentService studentService;
/**
* 构造方法,给代理的真实对象赋值
* @param studentService
*/
public InvocationHandlerImpl(StudentService studentService) {
this.studentService = studentService;
}
/**
* 该方法负责集中处理动态代理类上的所有方法的调用
* 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
* @param proxy 代理类实例
* @param method 被调用的方法对象
* @param args 调用参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("扩展1");
// 当代理对象调用真实对象的方法时, 会自动跳转到代理对象关联的handler对象的invoke方法来进行调用
Object invoke = method.invoke(studentService, args);
System.out.println("扩展2");
return invoke;
}
}
以上步骤,代理已经实现,接下来进行测试
/**
* 演示动态代理
*/
public class StudentServiceProxyTest {
public static void main(String[] args) {
// 创建代理的真实对象
StudentService studentServiceImpl = new StudentServiceImpl();
// 要代理哪个对象,就传入该对象,最后同过真实对象来调用方法
InvocationHandlerImpl handler = new InvocationHandlerImpl(studentServiceImpl);
// 得到类加载器与接口
ClassLoader loader = studentServiceImpl.getClass().getClassLoader();
Class<?>[] interfaces = studentServiceImpl.getClass().getInterfaces();
// 利用该方法为指定类加载器,接口,以及处理器生成动态代理类实例
StudentService studentService = (StudentService) Proxy.newProxyInstance(loader, interfaces, handler);
System.out.println("studentService.getClass().getName() = " + studentService.getClass().getName());
// 调用代理类方法
studentService.play();
}
}
运行结果
jdk动态代理实现成功
2.2.cglib动态代理
cglib的动态代理实现比较简单,它需要的是一个类,我们定义一个学生类
/**
* 学生类
*/
public class Student {
public void study(){
System.out.println("学生爱学习");
}
public void play(){
System.out.println("学生爱玩耍");
}
}
再重写该学生类并增强
/**
* 学生代理类
*/
public class StudentProxy extends Student{
@Override
public void study() {
System.out.println("增强学习1");
super.study();
System.out.println("增强学习2");
}
@Override
public void play() {
System.out.println("增强玩耍1");
super.play();
System.out.println("增强玩耍2");
}
}
该子类就是cglib的动态代理类,同样实现了代理以及增强,这就是cglib实现动态代理的原理。