代理模式

	艺术来源于生活,程序亦是如此。
	房产中介在我们的生活中广泛存在,这就是代理模式在生活中非常明显的例子;一般情况下,买房子,租房子都是找中介,在合理合法的范围内,能够降低交易过程中的各种成本。

静态代理

首先我们需要明白两个概念:代理对象和目标对象。
在买房子的过程中,目标对象就是最终的交易物:房子,代理对象就是房产中介,代理对象会帮我们达到买房的目的,同时会对买房子的过程进行相应的过程增强,比如怎么批贷款更加方便,哪家贷款的利息更加低之类的。
回到程序,在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类
举个例子来说明这个过程,打印日志是开发过程中非常常见的操作,这里我们就模拟打印日志的操作

日志接口

public interface ILogger {
    //日志打印方法
    void logger();
}

目标对象

public class Logger implements ILogger {
    @Override
    public void logger() {
        System.out.println("打印日志");
    }
}

代理对象

public class ProxyLogger implements ILogger {
    private ILogger logger;

    public ProxyLogger(Logger logger) {
        this.logger = logger;
    }

    @Override
    public void logger() {
        System.out.println("查询前执行的逻辑:查看当前的参数");
        logger.logger();
        System.out.println("查询后执行的逻辑:保存查询的参数");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        Logger logger = new Logger();
        ProxyLogger proxyLogger = new ProxyLogger(logger);
        proxyLogger.logger();
        //运行结果
        //查询前执行的逻辑:查看当前的参数
        //打印日志
        //查询后执行的逻辑:保存查询的参数
    }
}

总结

静态代理的优点:可以对目标对象进行增强,不会修改原有的逻辑。
缺点:因为代理对象需要实现跟目标对象一样的接口,所以会产生很多代理类;
如果接口或者父类增加方法,目标对象和代理对象都需要维护,非常麻烦。

动态代理

怎么避免静态代理里面的缺点呢?
动态代理就可以解决这个问题!

jdk动态代理

特点
在程序运行时,通过反射机制动态生成;
代理对象不需要实现接口,但是目标对象需要实现一个接口。
代理工厂类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyFactory {
    //维护一个目标对象
    private Object target;
	//通过构造方法传入目标对象
    public ProxyFactory(Object target) {
        this.target = target;
    }

    //给目标对象生成代理对象
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("动态代理方法前");
                        //执行目标对象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("动态代理方法后");
                        return returnValue;
                    }
                }
        );
    }
}

日志类、接口

public interface ILogger {
    //日志打印方法
    void logger();
}
public class Logger implements ILogger {
    @Override
    public void logger() {
        System.out.println("打印日志");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        Logger logger = new Logger();
        ILogger proxy = (ILogger) new ProxyFactory(logger).getProxyInstance();
        proxy.logger();
        //运行结果
        //动态代理方法前
        //打印日志
        //动态代理方法后
    }
}

cglib动态代理

有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP,为他们提供方法的interception(拦截)

注意

  1. 代理的类不能为final,否则报错
  2. 目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法

代码示例

目标对象
public class Logger {
    public void logger() {
        System.out.println("打印日志");
    }
}
代理工厂
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

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 o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("打印日志前操作");
        Object result = method.invoke(target, objects);
        System.out.println("打印日志后操作");
        return result;
    }
}
测试类
public class Test {
    public static void main(String[] args) {
        Logger logger = new Logger();
        Logger proxyInstance = (Logger) new ProxyFactory(logger).getProxyInstance();
        proxyInstance.logger();
        //结果示例
        //打印日志前操作
        //打印日志
        //打印日志后操作
    }
}

总结

代码来源于生活,同时又高于生活
代理模式中比较重要的就是动态代理,jdk动态代理和cglib动态代理各有优缺点,需要自己对比去使用。
jdk动态代理需要目标对象实现一个接口,我们可以在接口里面自定义各种方法,符合面向接口编程规范。
cglib动态代理需要引入三方jar包,有点就是不需要实现接口,而是动态的为目标对象生成一个子类,再对子类做方法增强,因为是继承,所以目标对象的方法不能被final修饰,也不能被static修饰,不然不能做方法增强。
从效率上来说,当调用次数少的时候,也就是大部分情况下,jdk动态代理的性能优于cglib动态代理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值