Proxy和InvocationHandler实现自己的AOP

一、

spring Aop实际上也是通过动态代理机制进行面向切面编程的,在java里可以通过实现InvocationHandler接口建立自己的动态代理类,然后通过Proxy建立动态的代理类的对象。

动态代理其实就是java.lang.reflect.Proxy类动态的根据指定的所有接口生成一个class byte,该class会继承Proxy类,并实现所有你指定的接口(您在参数中传入的接口数组);然后再利用指定的classloader将 class byte加载进系统,最后生成这样一个类的对象,并初始化该对象的一些值,如invocationHandler,以即所有的接口对应的Method成员。 初始化之后将对象返回给调用的客户端。这样客户端拿到的就是一个实现你所有的接口的Proxy对象

首先InvocationHandler接口中只有一个方法

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

proxy:  指代我们所代理的那个真实对象
method:  指代的是我们所要调用真实对象的某个方法的Method对象
args:  指代的是调用真实对象某个方法时接受的参数

Proxy中动态创建实例的方法

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载

interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

二、

好了现在简单的模拟一下aop
首先新建一个接口

public interface Subject {

    public void rent();

    public void hello(String str);
}

对应的实现类

public class SubjectImpl implements Subject{

    @Override
    public void rent()
    {
        System.out.println("I want to rent my house");
    }

    @Override
    public void hello(String str)
    {
        System.out.println("hello: " + str);
    }

}
public class DynamicProxy implements InvocationHandler
{
    // 要代理的对象
    private Object target;

    // 将构造方法禁用掉,不让外部通过new来得到DynamicProxy对象
    private DynamicProxy()
    {
    };

    /**
     * 返回一个动态的代理对象
     * 
     * @param object
     * @return
     */
    public static Object newInstance(Object object)
    {
        DynamicProxy proxy = new DynamicProxy();
        proxy.target = object;
        //    通过Proxy的newProxyInstance方法来得到一个代理对象
        Object result = Proxy.newProxyInstance(object.getClass()
                .getClassLoader(), object.getClass().getInterfaces(), proxy);
        return result;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable
    {
//        //    只有方法名为add和delete时候才引入日志
//        if(method.getName().equals("add") || method.getName().equals("delete"))
//        {
//            Logger.logInfo("动态代理类");
//        }

        // 根据LogAnnotation来判断,如果被标注了注解,则输出日志
        if(method.isAnnotationPresent(LogAnnotation.class))
        {
            LogAnnotation log = method.getAnnotation(LogAnnotation.class);
            Logger.logInfo(log.value());
        }

        Object object = method.invoke(target, args);
        return object;
    }
}

然后是spring的配置

<!-- 如果要对static方法进行注入,可以通过factory-method属性来制定方法名字,并通过构造函数的方式传入参数 -->
        <bean id="userDAOProxy" class="com.xiaoluo.proxy.DynamicProxy" factory-method="newInstance">
            <constructor-arg ref="userDAO"/>
        </bean>

因为我们的DynamicProxy类的对象以及代理对象是通过static方法来进行注入的,因此我们如果要对其进行注入的话,需要通过 factory-method 这个属性来给我们的静态方法进行属性注入,通过 来讲参数传递进去,这样我们的userDAOProxy就是一个代理对象了

三、

关于InvocationHandler接口的invoke方法,其实这个类就是最终Proxy调用的固定接口方法。Proxy不管客户端的业务方法是怎么实现的。当客户端调用Proxy时,它只

会调用InvocationHandler的invoke接口,所以我们的真正实现的方法就必须在invoke方法中去调用。关系如下:

BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);

BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(....);

bp.processBusiness()-->invocationHandler.invoke()-->bpimpl.processBusiness();

Proxy.newProxyInstance方法会做如下几件事:

1,根据传入的第二个参数interfaces动态生成一个类,实现interfaces中的接口,该例中即BusinessProcessor接口的processBusiness方法。并且继承了Proxy类,重写了hashcode,toString,equals等三个方法。具体实现可参看 ProxyGenerator.generateProxyClass(…); 该例中生成了$Proxy0类

2,通过传入的第一个参数classloder将刚生成的类加载到jvm中。即将$Proxy0类load

3,利用第三个参数,调用 Proxy0 Proxy0(InvocationHandler)构造函数 创建$Proxy0的对象,并且用interfaces参数遍历其所有接口的方法,并生成Method对象初始化对象的几个Method成员变量

4,将$Proxy0的实例返回给客户端。

现在好了。我们再看客户端怎么调就清楚了。

1,客户端拿到的是 Proxy0 Proxy0继承了BusinessProcessor,因此转化为BusinessProcessor没任何问题。

BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(….);

2,bp.processBusiness();

实际上调用的是 Proxy0.processBusiness(); Proxy0.processBusiness()的实现就是通过InvocationHandler去调用invoke方法啦!

注:文章以自己记录为主,详细的可以去下面地方看

http://www.cnblogs.com/xiaoluo501395377/p/3384821.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值