代理模式是给某一个对象提供一个代理对象, 并由代理对象控制对原对象的引用, 通俗的来讲代理模式就是我们生活中常见的中介.
Spring 的 AOP 面向切面就是使用动态代理模式来实现的;
打个比方说: 我要买房, 但是我对该地区房屋的信息掌握的不够全面, 希望找一个更熟悉的人 (中介) 去帮我找, 此处的代理就是这个意思.
代理类分为静态代理类和动态代理类:
首先看下静态代理类, 代码如下:
接口:
- public interface Source {
- void method();
- }
委托类:
- /**
- * 委托类
- */
- public class RealSubject implements Source {
- @Override
- public void method() {
- System.out.println("我要去买房了");
- }
- }
1, 静态代理类:
- /**
- * 静态代理类
- */
- public class ProxySubject implements Source{
- private RealSubject realSubject;
- public ProxySubject() {
- this.realSubject = new RealSubject();
- }
- @Override
- public void method() {
- before();
- realSubject.method();
- after();
- }
- void before(){
- System.out.println("找房");
- }
- void after(){
- System.out.println("买房后装修");
- }
- }
测试类:
- public class Text {
- public static void main(String[] args) {
- Source source = new ProxySubject();
- source.method();
- }
- }
输出结果:
找房
我要去买房了
买房后装修
静态代理总结:
优点: 可以做到在符合开闭原则的情况下对目标对象进行功能扩展.
缺点: 我们得为每一个服务都创建代理类, 工作量太大, 不易管理. 同时接口一旦发生改变, 代理类也得相应修改.
2, 动态代理类
动态代理类中我们不需要手动的创建代理类, 我们只需要手动的编写一个动态处理器就可以了, 真正的代理对象由 JDK 在运行时为我们动态的进行创建;
Dynamic 代理模式相对于静态代理, 大大减少了我们的开发任务, 同时减少了对业务接口的依赖, 降低了耦合度;
动态代理的实现依靠于 InvocationHandler 接口和 Proxy 类来实现的, 每一个动态代理类中都必须要实现 InvocationHandler 接口, 该接口中有唯一的 invoke()方法;
该方法的作用就是得到一个动态的代理对象, 其接收三个参数:
loader: 第一个 ClassLoader 对象, 定义了由哪个 ClassLoader 对象来对生成的代理对象进行加载
interfaces: 第二个 Interface 对象的数组, 表示的是我将要给我需要代理的对象提供一组什么接口, 如果我提供了一组接口给它, 那么这个代理对象就宣称实现了该接口(多态), 这样我就能调用这组接口中的方法了
h: 第三个 InvocationHandler 对象, 表示的是当我这个动态代理对象在调用方法的时候, 会关联到哪一个 InvocationHandler 对象上
我们来看一下代码:
首先定义一个接口, 有两个方法
- public interface Source {
- void describe();
- void buyHourse();
- }
给该接口定义一个实现类, 其实就是我们的委托对象
- public class SourceImpl implements Source {
- @Override
- public void describe() {
- System.out.println("中國風");
- }
- @Override
- public void buyHourse() {
- System.out.println("购房");
- }
- }
定义动态代理类, 注意一定要实现接口 InvocationHandler
- public class DynamicProxy implements InvocationHandler{
- /** 这个就是要代理的委托对象, 使用 Object 类型, 可以代理不同类型的对象, 便于复用 */
- private Object source;
- /** 构造器, 给要代理的对象赋值 */
- public DynamicProxy(Object source) {
- this.source = source;
- }
- /*
- 我的理解: 当我们通过动态代理对象调用委托对象的方法时会执行该方法
- */
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- before();
- /* 当代理对象调用真实对象的方法时, 其会自动的跳转到代理对象关联的 handler 对象的 invoke 方法来进行调用 */
- method.invoke(source,args);
- after();
- return null;
- }
- void before(){
- System.out.println("调用对象方法前执行的业务逻辑");
- }
- void after(){
- System.out.println("调用对象方法后执行的业务逻辑");
- }
- }
测试类
- public class Test {
- public static void main(String[] args) {
- // 要代理的真实对象
- Source realSource = new SourceImpl();
- // 创建 handler 实例, 我们要代理哪个对象就把该对象传进去, 最后通过该真是对象来调用其方法
- InvocationHandler handler = new DynamicProxy(realSource);
- /**
- * 通过 Proxy.newProxyInstance 方法来创建代理对象,
- * 第一个参数是目标对象的类加载器, 获取方法为 geiClassLoader()
- * 第二个参数是一个 Interface 对象的数组, 表示的是将要给需要代理的对象提供一组什么借口,
- * 如果我提供了一组接口给它, 那么这个代理对象就可以实现该接口(多态),
- * 这样就能调用这组接口中的方法了
- * 这里我们为代理对象提供的接口是真实对象所实行的接口, 表示要代理的是该真是对象,
- * 这样就可以调用这组接口中的方法了
- * 第三个参数 handler, 指定的动态代理处理器, 将该动态处理器传入真实的代理对象, 即委托类对象
- */
- Source source = (Source) Proxy.newProxyInstance(Source.class.getClassLoader(),
- realSource.getClass().getInterfaces(),handler);
- source.describe();
- System.out.println("");
- source.buyHourse();
- }
- }
输出结果
调用对象方法前执行的业务逻辑
中國風
调用对象方法后执行的业务逻辑
调用对象方法前执行的业务逻辑
购房
调用对象方法后执行的业务逻辑
OK, 至此两个常见的代理模式就到这里了, 明天说一下使用第三方插件实现的 CGLIB 代理模式; 下班了回家!! 祝大家中秋节快乐!!!
来源: https://www.cnblogs.com/yueguanguanyun/p/9687886.html