设计模式-结构型-代理模式

代理模式

概念
代理(Proxy)是一种设计模式,通过代理对象去访问目标对象,不直接操作目标对象,可以增强功能。
场景
aop,拦截器,中介
组成
目标对象:被代理的对象,做最终的决定。
代理对象:目标对象的扩展,并会调用目标对象,通常引用目标对象。
用户对象:调用代理对象。
在这里插入图片描述
图来源:https://www.cnblogs.com/leeego-123/p/10995975.html

静态代理

在代理之前,目标对象是明确的。

// 目标接口
public interface Ilog {
    void print(String s);
}
//目标类
public class MyLog implements Ilog {
    @Override
    public void print(String s) {
    }
}
//静态代理类
public  class StaticProxyMyLog implements Ilog {
    private Ilog log;

    public StaticProxyMyLog(Ilog log) {
        this.log = log;
    }

    @Override
    public void print(String s) {
        // 方法增强 do something
        log.print(s);//执行目标方法
        // do something
    }
    //测试
    public static void main(String[] args) {
        Ilog target = new MyLog();//目标对象
        StaticProxyMyLog proxy = new StaticProxyMyLog(target);//代理对象持有目标引用
        proxy.print("--目标日志开始打印——");//执行的是增强的目标对象方法

    }
}

静态代理总结
1.在不修改目标对象方法的前提下,可以对方法增强。
2.因为代理对象需要实现接口所有方法,在修改接口或者代理类较多的情况下不利于维护,所以出现了动态代理模式。

动态代理

在代理之前,目标对象是不明确的,通过接口调用。

/**
 * 动态代理
 */
public  class DynamicProxy  {
    private Ilog target;

    public DynamicProxy(Ilog target) {
        this.target = target;
    }
    public  Ilog getInstace(){
        ClassLoader classLoader = this.getClass().getClassLoader();
        Ilog proxyLog = (Ilog)Proxy.newProxyInstance(classLoader, this.getClass().getInterfaces(),(proxy,method,args)->{
            Object obj = method.invoke(args);
            return obj;
        });
        return proxyLog;
    }

    //测试
    public static void main(String[] args) {
        // 代理对象持有目标对象引用
        DynamicProxy dynamic = new DynamicProxy(new MyLog());
        // 代理对象执行增强目标方法
        dynamic.getInstace().print("动态代理,代理类不需要实现目标接口");
    }

}

动态代理总结
1.代理对象不需要实现接口方法
2.目标对象需要实现接口,否则无法代理(cglib不需要)
3代理对象,是通过jdk的api构建了代理对象并加载到jvm中(需要指定代理的目标对象)
4.所以代理对象又被称为jdk代理,接口代理

JDK中生成代理对象的API
代理类所在包:java.lang.reflect.Proxy
JDK实现代理只需要使用Proxy#newProxyInstance方法

/*
* loader 指定当前目标对象使用类加载器,获取加载器的方法是固定的
* interfaces 目标对象实现的接口的类型,使用泛型方式确认类型
* h 事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
*/
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

Cglib

目标对象没有实现接口。目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理。

Cglib子类代理实现方法
1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入spring-core-x.x.x.jar
2.引入功能包后,就可以在内存中动态构建子类
3.代理的类不能为final,否则报错
4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法

在Spring的AOP编程中:
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用Cglib代理

/**
 * 目标对象,没有实现任何接口
 */
public class UserDao {

    public void save() {
        System.out.println("----已经保存数据!----");
    }
}
/**
 * Cglib子类代理工厂
 * 对UserDao在内存中动态构建一个子类对象
 */
public class ProxyFactory implements MethodInterceptor{
    //维护目标对象
    private Object target;

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

    //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();

    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开始事务...");

        //执行目标对象的方法
        Object returnValue = method.invoke(target, args);

        System.out.println("提交事务...");

        return returnValue;
    }
}
/**
 * 测试类
 */
public class App {

    @Test
    public void test(){
        //目标对象
        UserDao target = new UserDao();

        //代理对象
        UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();

        //执行代理对象的方法
        proxy.save();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值