动态代理

Posted guoDaXia的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态代理相关的知识,希望对你有一定的参考价值。

增强的手段
1、继承
*被增强对象不能变
*增强内容不能变
2.装饰者模式
*被增强对象可变
*但增强内容不可变
3.动态代理
*被增强对象可变
*增强内容可变

 

首先一个方法:

Proxy.newProxyInstance(ClassLoader classLoader,Class[] interfaces,invocationHandler h);

1、方法作用:动态创建实现了interfaces数组中所有指定接口的实现类对象!

参数:

1、ClassLoader:类加载器
它是用来加载类的,把.class文件加载到内存形成Class对象!
2、Class[] interfaces:指定要执行的接口
3、invocationHandler:代理对象的所有方法(个别方法不执行)都会调用InvocationHandler的invoke方法

 

第一个测试类:

package com.itcast.demo1;

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

import org.junit.Test;

public class Demo1 {
    @Test
    public void fun1(){
        /*
         * 三大参数
         * 1.ClassLoader
         * 方法需要动态生成一个类,这个类实现了A、B接口,然后创建这个类的对象!
         * 需要生成一个类,这个类也需要加载到方法区中,谁来加载,当然是ClassLoader
         *
         * 2.Class[] interfaces
         * 它是要实现的接口们
         * 
         * 3.InvocationHandler
         * 它是调用处理器
         * 敷衍它
         * 
         * 代理对象的所有方法都是调用invocationHandler的invoke方法
         */
        ClassLoader loader=this.getClass().getClassLoader();
        InvocationHandler h=new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                System.out.println("你好,动态代理!");
                return null;
            }
        };
        //使用三大参数创建代理对象
        Object o=Proxy.newProxyInstance(loader, new Class[]{A.class,B.class}, h);
        
        //强转成A和B类型,成功了!
        A a=(A) o;
        B b=(B) o;
        a.a();
        b.b();
        a.aa();
        b.bb();
        System.out.println(a.getClass().getName());
        
    }
}
interface A{
    public void a();
    public void aa();
}
interface B{
    public void b();
    public void bb();
}

证实几点:

  1、该方法生成了实现指定接口的代理对象。

  2、代理类的几乎所有方法的执行都是调用invocation的invoke方法。

  3、类加载器使用this.getClass().getClassLoader()得到。

 

动态代理的作用
最终是学习AOP(面向切面编程),它与装饰者模式有点相似,它比装饰者模式还要灵活!

 

方法:

public Object invoke(Object proxy,Method method,Object[] args)

这个invoke方法什么时候被调用!
1、在代理对象呗创建时?错误的
2、在调用代理对象所实现接口中的方法时?正确的!

*Object proxy:当前对象,即代理对象!在调用谁的方法!
*Method method:当前被调用的方法(目标方法)
*Object[] args:实参!

 

实现

(*被增强对象可变*但增强内容不可变):

package com.itcast.demo2;
//服务员
public interface Waiter {
    //服务
    public void server();

}

package com.itcast.demo2;

public class ManWaiter implements Waiter {

    @Override
    public void server() {
        System.out.println("服务中!");
    }

}

package com.itcast.demo2;

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

import org.junit.Test;
/**
 * 我们必须要掌握的是当前这个案例!
 * @author Administrator
 *
 */
public class Demo2 {

    @Test
    public void fun1(){
        Waiter manWaiter=new ManWaiter();
        /*
         * 给出三个参数,来调用方法得到代理对象
         */
        ClassLoader loader=this.getClass().getClassLoader();
        Class[] interfaces={Waiter.class};
        InvocationHandler h=new WaitInvocationHanlder(manWaiter); //被增强的目标对象
        Waiter waiter=(Waiter) Proxy.newProxyInstance(loader, interfaces, h);
        
        waiter.server();//前面加你好,后面加再见
    }
    
}
class WaitInvocationHanlder implements InvocationHandler{
    private Waiter waiter;//目标对象
    public WaitInvocationHanlder(Waiter waiter){
        this.setWaiter(waiter);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("你好!");
        this.waiter.server();//调用目标对象的方法
        System.out.println("再见!");
        return null;//return 的值是执行的方法的返回值,这个方法的proxy表示的是本代理对象,所以不能使用method.invoke(proxy,args).这样会走死循环。
    }

    public void setWaiter(Waiter waiter) {
        this.waiter = waiter;
    }

    public Waiter getWaiter() {
        return waiter;
    }
    
}

 

 

使用工厂模式,实现增强内容也可变。

目标对象:被增强的对象
代理对象:需要增强的对象,
目标:

  执行前增强

  执行后增强

 

package com.itcast.demo3;
/**
 * 前置增强
 */
public interface BeforeAdvice {
    public void before();

}

package com.itcast.demo3;
/*
 * 后置增强
 */
public interface AfterAdvice {
    
    public void after();
}

package com.itcast.demo3;

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

/**
 * 它用来生成代理对象
 * 它需要所有的参数
 *     *目标对象
 *  *增强
 */
/**
 * 1、创建代理工厂
 * 2、改工厂设置三样东西:
 *     *目标对象setTargetObject
 *     *前置增强:setBeforeAdvice
 *     *后置增强:setAfterAdvice
 * 3、调用createProxy()得到代理对象
 *     *执行代理对象方法时:
 *         执行BeforeAdvice的before()
 *         目标对象的目标方法
 *         执行AfterAdvice的after()
 */
public class ProxyFactory {
    private Object targetObject;//目标对象
    private BeforeAdvice beforeAdvice;//前置增强
    private AfterAdvice afterAdvice;//后置增强
    public Object getTargetObject() {
        return targetObject;
    }
    
    /**
     * 用来生成代理对象
     * @return
     */
    public Object createProxy(){
        /*
         * 给出三大参数
         */
        ClassLoader loader=this.getClass().getClassLoader();
        Class[] interfaces=targetObject.getClass().getInterfaces();
        InvocationHandler h=new InvocationHandler() {
            
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                /*
                 * 在调用代理对象的方法时,执行这里的内容
                 */
                //执行前置增强
                if(beforeAdvice!=null){
                    beforeAdvice.before();
                }
            Object result=method.invoke(targetObject, args);//执行目标对象的目标方法
                //执行后置增强
                if(afterAdvice!=null){
                    afterAdvice.after();
                }
                //返回目标对象中的返回值
                return result;
            }
        };
        
        //得到代理对象
        Object obj=Proxy.newProxyInstance(loader, interfaces, h);
        
        //返回代理
        return obj;
    }
    
    
    
    public void setTargetObject(Object targetObject) {
        this.targetObject = targetObject;
    }
    public BeforeAdvice getBeforeAdvice() {
        return beforeAdvice;
    }
    public void setBeforeAdvice(BeforeAdvice beforeAdvice) {
        this.beforeAdvice = beforeAdvice;
    }
    public AfterAdvice getAfterAdvice() {
        return afterAdvice;
    }
    public void setAfterAdvice(AfterAdvice afterAdvice) {
        this.afterAdvice = afterAdvice;
    }
    

}

主要代码就这些:

这里实现增强内容可变的方法是代理对象的执行体令它是可变的,所以使用工厂进行创建,进行了一些包装操作。我们必须透彻理解如何进行的增强,增强的步骤等。

难点在于:

  1、思路。明确知道自己需要什么怎么办。

  2、proxy中的invoke方法的书写。

以上是关于动态代理的主要内容,如果未能解决你的问题,请参考以下文章

动态 Rstudio 代码片段

是否可以动态编译和执行 C# 代码片段?

支持动态或静态片段的不同屏幕尺寸?

Forge Viewer - 如何在场景中访问(或获取渲染/片段代理)克隆的网格?

在ansible模板中使用动态组名称

代理模式(动态)