黑马程序员_Java基础_动态代理

------- android培训java培训、期待与您交流! -------


我们先了解一下什么是代理?


生活中的代理:
代理在我们的生活中很常见 ,比如生活中的一些事情:
生活中,我们不会直接去生产产品的工厂去直接购买产品,我们会直接从代理商(超市,专卖店等)直接购买,
而不用直接去工厂购买,所以省去了不少麻烦;

程序中的代理:
要为已存在的多个具有相同接口的目标类的各个方法、增加一些系统功能,
例如:处理异常、日志、计算方法的运算时间、事务管理、等等
 怎么做?
 编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标的相同方法,并在调用方法时加上系统功能的代码
 
 如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,
 在配置文件中配置是使用目标类,还是代理类,这样以后很容易切换
 比如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易
例子1:  我们通过代理类Proxy去获取代理Collection.class中的所有方法,并打印在控制台中,并带有参数的

public class ProxyTest {
    public static void main(String[] args) {
        Class<?> clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),
                Collection.class);
        System.out.println(clazz.getName());
        // 输出:$Proxy0
        
        ConstructorList(clazz);
        MethodList(clazz);
    }
    //动态代理的所有方法
    public static void MethodList(Class clazz){
        System.out.println("-----------MethodList------------");
        Method[] methods = clazz.getMethods();
        StringBuilder sbuid = new StringBuilder();
        for (Method method : methods) {
            sbuid.append(method.getName());
            sbuid.append("(");
            
            Class[] clazzTypes = method.getParameterTypes();
            for (Class classType : clazzTypes) {
                sbuid.append(classType.getName()+",");
            }
            if(clazzTypes.length != 0)
                sbuid.deleteCharAt(sbuid.lastIndexOf(","));
            sbuid.append(")");
            
            System.out.println(sbuid);
            sbuid.delete(0, sbuid.length());
        }
    }
    
    // 动态代理类的构造方法
    public static  void ConstructorList(Class clazz) {
        System.out.println("-----------ConstructorList------------");
        Constructor[] constructors = clazz.getConstructors();
        StringBuilder sbuid = new StringBuilder();
        for (Constructor constructor : constructors) {
            sbuid.append(constructor.getName());
            sbuid.append("(");
            
            Class[] clazzTypes = constructor.getParameterTypes();
            for (Class classType : clazzTypes) {
                sbuid.append(classType.getName()+",");
            }
            if(clazzTypes.length != 0)
                sbuid.deleteCharAt(sbuid.lastIndexOf(","));
            sbuid.append(")");
            
            System.out.println(sbuid);
        }
    }
}
扩展知识点:
JVM可以在运行期间动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类
JVM生成的动态类必须实现一个或多个接口,所有,JVM生成的动态类只能用作具有相同接口的目标类的代理
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,
所以,如果要为一个实现接口的类生成动态代理类,那么可以使用CGLIB库


 例子2:

动态代理类三中的实现方式:
1.获取代理.class
2.获取代理构造方法
第一种方式:创建子类实现InvocationHandler接口
                      创建代理类   Constructor.newInstance(new InvocationHandler子类对象)
第二种方式:直接创建Constructor实现时创内部类
                      Constructor.newInstance(new InvocationHandler(){
       实现方法;
})
第三种方式:使用Proxy的newProxyInstance静态方法创建代理类

下面的例子就是演示代理的实现:

public class ProxyTerst2 {
    /**
     * @param args
     * @throws NoSuchMethodException 
     * @throws SecurityException 
     */
    public static void main(String[] args) throws Exception {
        //创建动态代理类
        
        
        Class<?> clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),
                Collection.class);
        Constructor constructor = clazz.getConstructor(InvocationHandler.class);
        
        //第一种方式:
        class MyInvocationHandler1 implements InvocationHandler{
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                // TODO Auto-generated method stub
                return null;
            }
        }
        Collection proxy1 = (Collection) constructor
                .newInstance(new MyInvocationHandler1());
        System.out.println(proxy1);  //输出null
        
        
        //第二种方式:使用匿名内部类
        Collection proxy2 = (Collection) constructor.newInstance(new InvocationHandler(){
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                // TODO Auto-generated method stub
                return null;
            }
            
        });
        System.out.println(proxy2);
        
        
        //第三种方式:使用Proxy的newProxyInstance()静态方法
        Collection proxy3 =  (Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(),
                new Class[]{Collection.class},
                new InvocationHandler() {
                    ArrayList list =new  ArrayList();
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        
                        //开始时间
                        long startTime = System.currentTimeMillis(); 
                        
                        Object revValue=  method.invoke(list, args);
                        
                        //结束时间
                        long endTime = System.currentTimeMillis(); 
                        System.out.println(method.getName()+" run of time : "+(endTime-startTime));
                        
                        return revValue;
                    }
                });
        
        proxy3.add("123");
        proxy3.add("456");
        proxy3.add("789");
        System.err.println(proxy3.size());
        System.out.println(proxy3.getClass().getName());
            
    }
}

  需求:自定义动态代理,在目标类的方法中添加时间计算

思想:
创建一个系统功能类的接口,并创建子类去实在
通过 使用Proxy的newProxyInstance静态方法去创建动态代理类
例子3: 
 第一部分:
public interface Advice {
    public void beforMethod(Method method);
    public void endMethod(Method method);
}
public class MyAdvice implements Advice {
    private long startTime = 0;
    @Override
    public void beforMethod(Method method) {
         this.startTime = System.currentTimeMillis(); 
    }
    @Override
    public void endMethod(Method method) {
        // TODO Auto-generated method stub
        long endTime = System.currentTimeMillis();
        System.out.println(method.getName()+" run of time :" +(endTime-this.startTime));
    }
}

 第二部分:创建代理类
public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    private Advice advice ;
    MyInvocationHandler(Object target,Advice advice) {
        this.advice = advice;
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        advice.beforMethod(method);
        Object retValue = method.invoke(target, args);
        advice.endMethod(method);
        return retValue;
    }
}

 测试部分:
public class MyInvocationHandlerTest {
    /**
     * @param args
     */
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        MyAdvice myAdvice = new MyAdvice();
        List proxy = (List) Proxy.newProxyInstance(list.getClass()
                .getClassLoader(), list.getClass().getInterfaces(),
                new MyInvocationHandler(list, myAdvice));
        proxy.add("123");
        proxy.add("456");
        proxy.add("789");
        System.out.println(proxy.size());
        System.out.println(proxy.getClass().getName());
        System.out.println(proxy.getClass().getClassLoader());
        /*
         * 输出结果:
         * add run of time :0
         *  add run of time :0
         *   add run of time :0 
         *   size run of time :0 
         *   3
         *    $Proxy0
         *     null
         */
        
    }
}

 需求:模仿Spring实现动态代理类,读取配置文件给目标类添加系统计时
 例子4:

配置文件:
 config.properties

需求:模仿Spring实现动态代理类,读取配置文件给目标类添加系统计时
例子4:
</pre><pre class="html" name="code"><span style="font: 14px/22.39px Arial; color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; -webkit-text-stroke-width: 0px;"><span style="color: rgb(255, 0, 0); font-weight: bold;"><span><span><span><span style="color: rgb(0, 0, 0); font-weight: normal;">配置文件:
<span> config.properties</span></span></span></span></span></span></span><div style="font: 14px/22.39px Arial; color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; -webkit-text-stroke-width: 0px;"> <div style="font: 14px/22.39px Arial; height: 14px; color: rgb(77, 77, 76); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; -webkit-text-stroke-width: 0px;">#<span style="color: rgb(77, 77, 76);">xxx</span><span style="color: rgb(62, 153, 159);">=</span><span style="color: rgb(77, 77, 76);">java</span>.<span style="color: rgb(77, 77, 76);">util</span>.<span style="color: rgb(77, 77, 76);">ArrayList</span></div><div style="font: 14px/22.39px Arial; height: 14px; color: rgb(77, 77, 76); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; -webkit-text-stroke-width: 0px;"><span style="color: rgb(77, 77, 76);">xxx</span><span style="color: rgb(62, 153, 159);">=</span><span style="color: rgb(77, 77, 76);">day15_Proxy</span>.<span style="color: rgb(77, 77, 76);">ProxyFactoryBean</span></div><div style="font: 14px/22.39px Arial; height: 14px; color: rgb(77, 77, 76); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; -webkit-text-stroke-width: 0px;"><span style="color: rgb(77, 77, 76);">xxx</span>.<span style="color: rgb(77, 77, 76);">advice</span><span style="color: rgb(62, 153, 159);">=</span><span style="color: rgb(77, 77, 76);">day15_Proxy</span>.<span style="color: rgb(77, 77, 76);">MyAdvice</span></div><div style="font: 14px/22.39px Arial; height: 14px; color: rgb(77, 77, 76); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; -webkit-text-stroke-width: 0px;"><span style="color: rgb(77, 77, 76);">xxx</span>.<span style="color: rgb(77, 77, 76);">target</span><span style="color: rgb(62, 153, 159);">=</span><span style="color: rgb(77, 77, 76);">java</span>.<span style="color: rgb(77, 77, 76);">util</span>.<span style="color: rgb(77, 77, 76);">ArrayList</span></div></div>

第一部分: 创建Bean工厂

public class BeanFactory {
    Properties prop = new Properties();
    
    public BeanFactory(InputStream in){
        try {
            prop.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    } 
    
    public Object getBean(String name){
        String className = prop.getProperty(name);
        Object bean = null;
        try {
            bean  = Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        } 
        if(bean instanceof ProxyFactoryBean){
            Object proxy = null;
            ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) bean;
            try {
                Object target = Class.forName(prop.getProperty(name+".target")).newInstance();
                Advice advice = (Advice) Class.forName(prop.getProperty(name+".advice")).newInstance();
                proxyFactoryBean.setAdvice(advice);
                proxyFactoryBean.setTarget(target);
                proxy = proxyFactoryBean.getProxy();
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("创建目标失败");
            }
            return proxy;
        }
        
        return bean;        
    }
}

 第二部分:创建代理工厂

public class ProxyFactoryBean {
    private Advice  advice;
    private Object target;
    public Object getProxy(){
        Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader()
                , target.getClass().getInterfaces(), new InvocationHandler() {
                    
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        advice.beforMethod(method);
                        Object retValue = method.invoke(target, args);
                        advice.endMethod(method);
                        return retValue;
                    }
                });
        return proxy;
    }
    public Advice getAdvice() {
        return advice;
    }
    public void setAdvice(Advice advice) {
        this.advice = advice;
    }
    public Object getTarget() {
        return target;
    }
    public void setTarget(Object target) {
        this.target = target;
    }
    
    
}

测试部分:

public class AopFrameworkTest {
    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        InputStream in = AopFrameworkTest.class.getResourceAsStream("config.properties");
        
        Object bean = new BeanFactory(in).getBean("xxx");
        
//      List list = (List)bean; 
        Collection list = (Collection)bean; 
        list.clear();
        list.add("123");
        list.add("456");
        System.out.println(list.size());
        System.out.println(bean.getClass().getName());  //输出:$Proxy0  实验成功
        
        /*
         * 输出结果:
         * clear run of time :1
            add run of time :0
            add run of time :0
            size run of time :0
            2
            $Proxy0
         */
    }
}









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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值