关于java:深入浅出设计模式代理模式

7次阅读

共计 3918 个字符,预计需要花费 10 分钟才能阅读完成。

1. 代理模式介绍

2. 用代码演示代理模式

3. 总结

1. 代理模式介绍

定义
1)代理模式,为代理对象提供一个替身,以管制这个对象的拜访,就是通过代理对象来拜访对象。这样做的益处是:能够在指标对象的根底上,再减少额定的加强操作。
2)被代理的对象能够是近程对象,创立开销大的字段和须要安全控制的字段
3)代理模式有三种不同的模式,动态代理,动静代理,和 cglib 代理。

形容
代理最驰名的应用场景就是人尽皆知的 AOP,就拿咱们很相熟的事务注解 @Transactional 来说,咱们晓得加上了这个注解后,函数办法就会成为事务操作。

咱们都晓得,用 sql 写事务的时候,如果咱们要进行事务操作,须要写两个这样的 sql 语句:

start transaction;

// 两头执行业务逻辑

commit;

这时咱们写好了两头的业务逻辑,加上注解之后,相当于把这个对象交给了一个代理对象,让代理对象执行开启事务和完结时的逻辑,咱们只有编写业务逻辑就好了。同时这个办法也失去了加强,有了前置和后置办法,有了事务的成果,加强额定的性能操作。

2. 用代码演示依代理模式

1)动态代理

动态代理模式的根本介绍:

动态代理在应用的时候,须要定义接口或者父类,被代理对象(指标对象)与代理对象一起实现独特的接口或者是继承雷同的父类。

具体要求
1)定义一个接口 ITeacherDao
2)指标对象 TeacherDAO 实现接口 ITeacherDAO
3)定义一个代理对象 TeacherProxy,也实现 ITeacherDao
4)调用的时候通过调用代理对象的办法来调用指标对象
5)代理对象与指标要实现雷同的接口,而后通过调用雷同的办法来调用指标对象的办法。

代码展现

ITeacherDao:


public interface ITeacherDao {void teach();// 授课的办法
}

TeacherDao:

public class TeacherDao implements ITeacherDao {
    @Override
    public void teach() {System.out.println("老师开始上课了!");
    }
}

TeacherProxy:

public class TeacherProxy implements ITeacherDao {

    // 先把要代理的对象传进来
    private ITeacherDao target = new TeacherDao();
    
    public TeacherProxy(ITeacherDao target) {this.target = target;}
    
    // 执行代理办法,在办法前后进行加强
    @Override
    public void teach() {System.out.println("代理开始");
        target.teach();
        System.out.println("代理完结");
    }
}
    public static void main(String[] args) {
        // 被代理对象
        ITeacherDao iTeacherDao = new TeacherDao();
        // 代理对象
        TeacherProxy teacherProxy = new TeacherProxy(iTeacherDao);
        // 执行代理对象的办法
        teacherProxy.teach();}

长处:合乎开闭准则,能对指标对象进行扩大。

毛病:为每一个须要加强的服务都须要创立类,容易造成类爆炸。

2)动静代理

动静代理根本介绍:

1)代理对象不须要实现接口,然而指标对象要实现接口,否则不能应用
2)代理对象的生成,是利用 jdk 的 api,动静的在内存中构建代理对象
3)动静代理也叫作:jdk 代理,接口代理

代码实现:

ITeacherDao:

public interface ITeacherDao {void teach();// 授课的办法
}

TeacherDao:

public class TeacherDao implements ITeacherDao {
    @Override
    public void teach() {System.out.println("老师开始上课了!");
    }
}

ProxyFactory:

public class ProxyFactory {

    // 保护一个指标对象
    private Object target;

    // 创立结构器对一个指标对象进行初始化
    public ProxyFactory(Object target) {this.target = target;}

    public Object getProxyInstance() {
        // 以后对象应用的指标类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();
        // 指标对象实现的接口类型,应用泛型的形式确认类型
        Class<?>[] classes = target.getClass().getInterfaces();
        // 执行指标对象的办法时,会登程事件解决办法,会把以后执行的对象当做参数传入
        InvocationHandler invocationHandler = null;
        return Proxy.newProxyInstance(classLoader, classes, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 加强逻辑
                System.out.println("JDK 代理开始");
                // 原办法执行逻辑,执行完之后返回值
                Object invoke = method.invoke(target, args);
                System.out.println("JDK 代理完结");
                return invoke;
            }
        });

    }
}

要留神一下 Proxy.newProxyInstance() 办法有三个参数,
Proxy.newProxyInstance()办法承受三个参数:

ClassLoader loader: 指定以后指标对象应用的类加载器, 获取加载器的办法是固定的

Class<?>[] interfaces: 指定指标对象实现的接口的类型, 应用泛型形式确认类型

InvocationHandler: 指定动静处理器,执行指标对象的办法时, 会触发事件处理器的办法

只须要依照上述的正文传入就能够了,用法也是非常简略。

长处:动静代理大大减少了咱们的开发工作, 同时缩小了业务接口依赖。

毛病:始终无奈解脱 interface 代理的枷锁,无奈实现对 class 的动静代理。

3)cglib 代理

1)须要引入 cglib 的依赖
2)通过字节码技术为一个类创立子类,并在子类中采纳办法拦挡的技术拦挡所有父类办法的调用,趁势织入横切逻辑。

代码展现:

TeacherDao:

public class TeacherDao {public void teach() {System.out.println("老师开始上课了!");
    }


}

CglibProxyFactory:

public class CglibProxyFactory implements MethodInterceptor {
    // 要加强的指标类
    private Object target;

    public CglibProxyFactory(Object target) {this.target = target;}

    public Object getProxyInstance() {
        // 创立工具类
        Enhancer enhancer = new Enhancer();
        // 设置父类
        enhancer.setSuperclass(target.getClass());
        // 设置回调函数
        enhancer.setCallback(this);
        // 创立子类对象,即代理对象
        return enhancer.create();}

    // 重写 intercept, 会调用指标对象的办法
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 加强的逻辑
        System.out.println("cglib 开始");
        // 执行结束后返回的参数
        Object invoke = methodProxy.invokeSuper(obj, args);
        // 加强的逻辑
        System.out.println("cglib 完结");
        // 返回参数
        return invoke;
    }

}

    public static void main(String[] args) {
        // 指标代理对象
        TeacherDao target = new TeacherDao();
        // 代理工厂
        CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(target);
        // 从代理工厂返回代理对象
        TeacherDao proxyInstance = (TeacherDao) cglibProxyFactory.getProxyInstance();
        // 执行代理对象的办法
        proxyInstance.teach();}

长处:能对 class 进行加强,CGLIB 创立的动静代理对象比 JDK 创立的动静代理对象的性能更高。

毛病:CGLIB 创立代理对象时所破费的工夫比 JDK 多得多,而且编码不是十分不便,同时因为 CGLib 因为是采纳动态创建子类的办法,对于 final 润饰的办法无奈进行代理。

3. 总结

代理模式就是 spring 底层 AOP 的实现办法,目标就是为了把一些加强切入到业务逻辑代码里,并将这个切面对立治理。

正文完
 0