java 动态代理

代理模式,顾名思义,就是找个代理人。就好像房产中介,当你看上一个房子想买的时候,并不是直接跟卖主联系,而是跟房产中介沟通,中介再来跟卖家沟通,最后的结果反映给买家。

1. 静态代理

静态代理就是需要程序员自己编写一个代理,在编译时这个类就已经存在了。
示例代码如下:

  1. 首先定义功能
interface Something{
    public void doSomething();
}
  1. 定义一个实现类
class Shopping implements Something{

    @Override
    public void doSomething() {
        System.out.println("I will go shop!");
    }
}
  1. 为实现类定义一个代理类
public class StaticAgent implements Something{
    private Shopping shopping;
    public StaticAgent(Shopping sp){
        shopping = sp;
    }
    @Override
    public void doSomething(){
        System.out.println("before I go shopping");
        shopping.doSomething();
        System.out.println("shoping is done");
    }
}
  1. 具体调用
    public static void main(String[] args) {
        Something agent = new StaticAgent(new Shopping());
        agent.doSomething();
    }

那么就有同学要问了,这个代理类好像并没有存在的必要啊。但是其实是有的,一般业务只是实现要实现的功能,但是如果有些操作需要在业务之外做,代理类就可以发挥作用了。就像我在代理类中写的那样,在执行业务代码前后增加了两条输出。同样可以用于执行其他的诸如日志记录、事务管理等。

2. 动态代理

前面所说的静态代理实现起来很简单,但是有个缺点就是所有的代理类都必须在代码中写出来。那假如很多类都需要增加相同的日志管理,就要针对所有的类都添加一个代理类,这样就有很多冗余的代码。动态代理的出现就解决了这个问题,它可以在运行时动态生成代理类,这样就可以为一类相同的代理只提供一个代理类,大大的减少了代码量。
动态代理主要有两种形式,一种是java本身提供的,使用InvocationHandler接口。另一种是使用cglib库来实现。前者是java利用反射获取需要实现的接口然后运行时动态生成代理实现类,后者则比较强大了,是利用ASM字节码操作框架来直接修改字节码从而生成代理类。后者速度要比前者快很多,而且可以对接口进行代理。但是无法为final方法进行代理。
本文先主要描述如何利用java提供的接口实现动态代理。
java提供的动态代理需要实现接口InvocationHandler.

public class AgentExecute implements InvocationHandler {
    private Object target;
    /**
     * 绑定对象
     * @param source
     * @return
     */
    public Object bind(Object source) {
        target = source;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = method.invoke(target, args);
            return result
    }
}

其中Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)可以为目标类的所有接口创建代理类。
loader为目标类的类加载器。
interfaces为目标类实现的所有接口。
h为代理类。一般为本实现类。
invoke函数为代理类调用的方法,当代理类调用需要实现的函数时,会利用反射动态的调用函数。可以在调用该函数前后增加代码。
具体调用代码为:

AgentExecute agent = new AgentExecute();
Work work = (Work)agent.bind(new DayWork());
work.doWork("tiang", 18);

你可能感兴趣的:(java 动态代理)