Java动态代理总结

简介:

在之前的代码调用阶段,我们用action调用service的方法实现业务即可。

由于之前在service中实现的业务可能不能够满足当先客户的要求,需要我们重新修改service中的方法,但是service的方法不只在我们这个模块使用,在其他模块也在调用,其他模块调用的时候,现有的service方法已经能够满足业务需求,所以我们不能只为了我们的业务而修改service,导致其他模块授影响。

那怎么办呢?

可以通过动态代理的方式,扩展我们的service中的方法实现,使得在原油的方法中增加更多的业务,而不是实际修改service中的方法,这种实现技术就叫做动态代理。

动态代理:在不修改原业务的基础上,基于原业务方法,进行重新的扩展,实现新的业务。

例如下面的例子:

1、 旧业务

买家调用action,购买衣服,衣服在数据库的标价为50元,购买流程就是简单的调用。

2、 新业务

在原先的价格上可以使用优惠券,但是这个功能在以前没有实现过,我们通过代理类,代理了原先的接口方法,在这个方法的基础上,修改了返回值。

 代理实现流程:

1、 书写代理类和代理方法,在代理方法中实现代理Proxy.newProxyInstance

2、 代理中需要的参数分别为:被代理的类的类加载器soneObjectclass.getClassLoader(),被代理类的所有实现接口new Class[] { Interface.class },句柄方法new InvocationHandler()

3、 在句柄方法中复写invoke方法,invoke方法的输入有3个参数Object proxy(代理类对象), Method method(被代理类的方法),Object[] args(被代理类方法的传入参数),在这个方法中,我们可以定制化的开发新的业务。

4、 获取代理类,强转成被代理的接口

5、 最后,我们可以像没被代理一样,调用接口的认可方法,方法被调用后,方法名和参数列表将被传入代理类的invoke方法中,进行新业务的逻辑流程。

 上代码:

IBoss.java

复制代码
/**
 * 这是一个业务的接口,这个接口中的业务就是返回衣服的价格
 * @author wilson
 *
 */
public interface IBoss {//接口
    int yifu(String size);
}
复制代码

Boss.java

复制代码
/**
 * 实现了卖衣服的接口
 * 自定义了自己的业务,卖裤子
 * @author wilson
 *
 */
public class Boss implements IBoss{
    public int yifu(String size){
        System.err.println("天猫小强旗舰店,老板给客户发快递----衣服型号:"+size);
        //这件衣服的价钱,从数据库读取
        return 50;
    }
    public void kuzi(){
        System.err.println("天猫小强旗舰店,老板给客户发快递----裤子");
    }
}
复制代码

SaleAction.java

复制代码
public class SaleAction {
    /**
     * 不使用代理,直接调用方法
     * 方法中规定什么业务,就只能调用什么业务,规定什么返回值,就只能输出什么返回值
     */
    @Test
    public void saleByBossSelf() throws Exception {
        IBoss boss = new Boss();
        System.out.println("老板自营!");
        int money = boss.yifu("xxl");// 老板自己卖衣服,不需要客服,结果就是没有聊天记录
        System.out.println("衣服成交价:" + money);
        /*
         程序输出:
         天猫小强旗舰店,老板给客户发快递----衣服型号:xxl
        老板自营!
        衣服成交价:50
         */
    }
}
复制代码

使用动态代理:

ProxyBoss.java

复制代码
public class ProxyBoss {
    /**
     * 对接口方法进行代理
     */
    @SuppressWarnings("unchecked")
    //写法一:通过参数传入代理对象的Class ,更灵活,更方便的适配
    public static <T> T getProxy(final int discountCoupon,final Class<?> interfaceClass, final Class<?> implementsClass)
        throws Exception {
            return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),new Class[] { interfaceClass }, new InvocationHandler() {
                    public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {
                        Integer returnValue = (Integer) method.invoke(implementsClass.newInstance(), args);// 调用原始对象以后返回的值
                        return returnValue - discountCoupon;
                    }
                });
    }
    //写法二:在方法内部指定对象的Class
    public static IBoss getProxyBoss(final int discountCoupon) throws Exception {
        Object proxedObj = Proxy.newProxyInstance(Boss.class.getClassLoader(),new Class[] { IBoss.class }, new InvocationHandler() {
            public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {
                    Integer returnValue = (Integer) method.invoke(new Boss(),args);// 调用原始对象以后返回的值
                    return returnValue - discountCoupon;
            }
        });
        return (IBoss)proxedObj;
    }
}
复制代码

调用动态代理:

ProxySaleAction.java

复制代码
/**
 * 什么是动态代理? 简单的写一个模板接口,剩下的个性化工作,好给动态代理来完成!
 */
public class ProxySaleAction {
    
    /**
     *使用代理,在这个代理中,只代理了Boss的yifu方法
     *定制化业务,可以改变原接口的参数、返回值等
     */
    @Test
    public void saleByProxy() throws Exception {
        /*
         *  将代理的方法实例化成接口  10是要打折的价格数
         *  如下这种写法对应的是ProxyBoss.java中的public static <T> T getProxy(final int...这种方法
         *  IBoss boss = ProxyBoss.getProxy(10,IBoss.class,Boss.class);
         */
        //如下这种写法对应的是ProxyBoss.java中的public static IBoss getProxyBoss(final int 这种方法....
        IBoss boss = ProxyBoss.getProxyBoss(10);// 将代理的方法实例化成接口
        System.out.println("代理经营!");
        //调用接口的方法,实际上调用方式没有变 调用了invoke()方法
        int money = boss.yifu("xxl");
        System.out.println("衣服成交价:" + money);
        /*
         程序输出:
        代理经营!
        衣服成交价:40
        天猫小强旗舰店,老板给客户发快递----衣服型号:xxl
         */
    }
}
复制代码

//==================另外一个总结=======================

上代码:

Waiter.java

public interface Waiter {
    public void server();
    public String sayHello(String name);

}

GirWaiter.java

复制代码
public class GirlWaiter implements Waiter{
    @Override
    public void server() {
        System.out.println("服务中………………");
    }

    @Override
    public String sayHello(String name) {
        return "Hello"+name;
    }
}
复制代码

ProxyDemo2.java

复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.junit.Test;

public class ProxyDemo2 {
    @Test
    public void demo1(){
        //用当前的java类文件来获得ClassLoader对象.
        ClassLoader loader = ProxyDemo2.class.getClassLoader();
        //这是个数组,要用大括号括起来,而且返回的得到的是Class对象.
        Class[] interfaces = {Waiter.class}; 
        /**
           loader - 定义代理类的类加载器      interfaces - 代理类要实现的接口列表
            h - 指派方法调用的调用处理程序
           
           
           newProxyInstance方法中需要传递三个参数:
               * loader:
               * interfaces:代理类要实现的接口列表
            * h:  h - 指派方法调用的调用处理程序
                * 应付一下:
                    * ClassLoader:
                    * Class[]
            
            返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。此方法相当于: 
         Proxy.getProxyClass(loader, interfaces).
         getConstructor(new Class[] { InvocationHandler.class }).
         newInstance(new Object[] { handler });
            
            想为Waiter接口的一个实现类生成一个代理.就需要传入你这个类的实现接口的class.为什么是一个数组,一个类可以实现多个接口.
            想生成这个Waiter接口的代理类....传入Waiter.class
            
            Proxy.newProxyInstance返回的是个Object类型,需要去强转
            MyInvocationHandler类中没有含有参数的构造方法,所以在new一个MyInvocationHandler的时候 一定要传入一个参数.
            这样才能编译通过.才能真正new出一个MyInvocationHandler对象. 
         */    
        Waiter waiter = (Waiter) Proxy.newProxyInstance(loader, interfaces, new MyInvocationHandler(new GirlWaiter()));
        
        //调用waiter中的方法就相当域调用invoke的方法.
        waiter.server();
        String s = waiter.sayHello("张三");
        System.out.println(s);
    }
}

//InvocationHandler 是代理实例的调用处理程序 实现的接口。
class MyInvocationHandler implements InvocationHandler{
    /*
    //在这个MyInvocationHandler的构造方法中传入一个GirlWaiter对象
    public MyInvocationHandler(GirlWaiter girlWaiter){
        
    }
    */
    
    /*
     对这个接口生成了一个代理类了....到底是生成一个接口的代理类还是生成这个接口的实现类的代理类....
    两个都可以,但是接口相当于其实现类的父类  但是接口更通用...所以一般都是生成接口的代理类.
     */
    private Waiter waiter;
    public MyInvocationHandler(Waiter waiter){//传入参数的这个地方也用接口来做,更通用.
        this.waiter = waiter;
    }
    
    
    @Override
    /**不要忘记invoke()方法也是有参数的!!
     * invoke方法:
     *     * 调用waiter的某个方法都相当于调用invoke方法.
     *         * invoke方法的参数:
     *             * proxy:代理对象.
     *             * method:正在执行的方法.
     *             * args:方法的参数列表.
     */
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        
        //只想增强一个固定的方法,方法名是固定的,通过if判断进行筛选...
        /*
         * debug....
         * demo1中waiter.server() 的时候
         * method.getName = server ; args = null ; obj = null;
         * demo1中waiter.sayHello("张三");
         * method.getName = sayHello ; args = '张三' ; obj = "Hello张三"
         */
        Object obj = null;
        if("server".equals(method.getName())){
            System.out.println("微笑");
            obj = method.invoke(waiter,args);
        }else{
            obj = method.invoke(waiter,args);
        }
        return obj;
    }
}
复制代码

 运行输出:

微笑
服务中………………
Hello张三

PS:之间总结的关于静态代理的博文 


本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/6855599.html,如需转载请自行联系原作者

相关文章
|
4月前
|
缓存 安全 Java
Java中动态代理使用与原理详解
Java中动态代理使用与原理详解
53 0
|
4月前
|
Java
Java之动态代理的详细解析
2. 动态代理 2.1 好处: 无侵入式的给方法增强功能 2.2 动态代理三要素: 1,真正干活的对象
38 0
|
4月前
|
Java
【Java动态代理】—— 每天一点小知识
【Java动态代理】—— 每天一点小知识
|
5月前
|
Arthas Dubbo Java
Alibaba Java诊断工具Arthas查看Dubbo动态代理类
Alibaba Java诊断工具Arthas查看Dubbo动态代理类
55 0
|
4天前
|
设计模式 Java 索引
由反射引出的Java动态代理与静态代理
由反射引出的Java动态代理与静态代理
12 0
|
9天前
|
监控 Java 开发者
掌握 Java 反射和动态代理
【4月更文挑战第19天】Java反射和动态代理提供强大功能和灵活性。反射允许运行时检查和操作类,获取类信息、动态调用方法,但可能带来性能损失和降低代码可读性。动态代理则用于创建代理对象,实现透明性和横切关注点分离,常用于日志、权限检查等。两者结合能实现更复杂功能。掌握这些技术能提升代码的灵活性和可扩展性,但也需注意性能和可读性。通过学习和实践,能更好地构建高效软件系统。
|
1月前
|
Java API 开发者
Java代理模式——静态代理与动态代理
Java代理模式——静态代理与动态代理
27 1
|
1月前
|
监控 Java 程序员
java的动态代理如何实现
java的动态代理如何实现
25 0
|
2月前
|
设计模式 Java 程序员
Java动态代理
Java动态代理详解
|
2月前
|
Java
Java动态代理简易说明
Java动态代理简易说明
10 0