介绍
代理模式通过创建一个代理类,来对目标类进行增强。这样可以在不修改目标类的情况下进行扩展。比如在对目标对象的某个方法前后执行一些操作。
而代理模式分为静态代理和动态代理,动态代理主要有jdk动态代理和cjlib动态代理。其中jdk动态代理是java自带的,不需要额外的引入第三方包;而cjlib动态代理属于一个开源项目,使用的话需要导入相关依赖。
静态代理
特点
- 静态代理在编译期间就将接口、实现类、代理类都编译成一个个class文件。
- 静态代理对每个方法增强都需要自己手动实现,并且目标类和代理类都需要进行修改。所以在日常使用中很少使用,以至于基本看不到。
- 静态代理需要对每一个目标类单独写一个代理类。
实现方式
- 定义一个接口及其实现类;
- 创建一个代理类同样实现这个接口
- 将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法(可以在调用前后添加自己的需要的代码)。
代码实现
1.定义接口
public interface HelloService {
void hello();
}
2.实现类
public class HelloServiceImpl implements HelloService{
@Override
public void hello() {
System.out.println("hello world!");
}
}
3.创建代理类并同样实现接口
通过构造函数注入需要代理的目标类
public class HelloProxy implements HelloService{
private final HelloService helloService;
public HelloProxy(HelloService helloService){
this.helloService = helloService;
}
@Override
public void hello() {
System.out.println("before......");
helloService.hello();
System.out.println("after......");
}
}
- 测试类
public class HelloMainTest {
public static void main(String[] args) {
HelloService helloService = new HelloServiceImpl();
HelloProxy helloProxy = new HelloProxy(helloService);
helloProxy.hello();
}
}
5.执行结果
before......
hello world!
after......
jdk动态代理
jdk动态代理用到InvocationHandler
接口和Proxy
类。其Proxy
类中的newProxyInstance()
方法是关键,该方法用来生成一个代理对象。
public static Object newProxyInstance(
ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
- loader :类加载器,用于加载代理对象。
- interfaces : 被代理类实现的一些接口;
- h : 实现了
InvocationHandler
接口的对象;
要实现动态代理的话,还必须需要实现InvocationHandler
来自定义处理逻辑。 当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler
接口类的 invoke
方法来调用。
public Object invoke(Object proxy, Method method, Object[] args)
- proxy :动态生成的代理类
- method : 与代理类对象调用的方法相对应
- args : 当前 method 方法的参数
你通过
Proxy
类的newProxyInstance()
创建的代理对象在调用方法的时候,实际会调用到实现InvocationHandler
接口的类的invoke()
方法。可以在invoke()
方法中自定义代码逻辑。
代码实现
- 定义一个接口及其实现类;
- 自定义
InvocationHandler
并重写invoke
方法,在invoke
方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑; - 通过
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
方法创建代理对象(一般是通过工厂模式来创建对象)
定义接口
public interface HelloService {
void hello();
}
接口实现类
public class HelloServiceImpl implements HelloService {
@Override
public void hello() {
System.out.println("hello......");
}
}
创建代理类并实现InvocationHandler
接口
public class HelloJdkProxy implements InvocationHandler {
private final Object target;
public HelloJdkProxy(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用方法之前,我们可以添加自己的操作
System.out.println("before method " + method.getName());
Object result = method.invoke(target, args);
//调用方法之后,我们同样可以添加自己的操作
System.out.println("after method " + method.getName());
return result;
}
}
这里通过工厂类来创建代理对象
public class JdkProxyFactory {
public static Object getJdkProxy(Object target){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目标类的类加载
target.getClass().getInterfaces(), // 代理需要实现的接口,可指定多个
new HelloJdkProxy(target) // 代理对象对应的自定义 InvocationHandler
);
}
}
测试
public class TestMainProxy {
public static void main(String[] args) {
HelloService jdkProxy = (HelloService)JdkProxyFactory.getJdkProxy(new HelloServiceImpl());
jdkProxy.hello();
}
}
运行结果
before method hello
hello......
after method hello
CJLIB动态代理
对于jdk动态代理,代理的对象必须是一个实现接口的类,这就存在了很大的限制,而CJLIB动态代理没有可以解决这个问题。
实现步骤
- 定义一个类;
- 自定义
MethodInterceptor
并重写intercept
方法,intercept
用于拦截增强被代理类的方法,和 JDK 动态代理中的invoke
方法类似; - 通过
Enhancer
类的create()
创建代理类;
添加依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
目标类
public class HelloService {
public void hello(){
System.out.println("hello ......");
}
}
代理类
public class HelloProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//调用方法之前,我们可以添加自己的操作
System.out.println("before method ......");
Object object = methodProxy.invokeSuper(o, objects);
//调用方法之后,我们同样可以添加自己的操作
System.out.println("before method ......");
return object;
}
}
获取代理对象的工厂类
public class CjlibProxyFactory {
public static Object getProxy(Class<?> clazz){
// 创建动态代理增强类
Enhancer enhancer = new Enhancer();
// 设置类加载器
enhancer.setClassLoader(clazz.getClassLoader());
// 设置被代理类
enhancer.setSuperclass(clazz);
// 设置方法拦截器
enhancer.setCallback(new HelloProxy());
// 创建代理类
return enhancer.create();
}
}
测试类
public class TestMainProxy {
public static void main(String[] args) {
HelloService proxy = (HelloService)CjlibProxyFactory.getProxy(HelloService.class);
proxy.hello();
}
}
执行结果
before method ......
hello ......
before method ......
评论区