在之前的代码调用阶段,我们用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:之间总结的关于静态代理的博文

http://www.cnblogs.com/DreamDrive/p/4005069.html

Java动态代理总结的更多相关文章

  1. Java 动态代理机制详解

    在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...

  2. Java动态代理全面分析

    代理模式 解说:给某一个对象提供一个代理,并由代理对象控制对原对象的引用: 代理模式需要以下几个角色: 1  主题:规定代理类和真实对象共同对外暴露的接口: 2  代理类:专门代理真实对象的类: 3 ...

  3. JAVA动态代理模式(从现实生活角度理解代码原理)

    所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联. java动态代理主要是使用java.lang.reflect包中的两个 ...

  4. Java 动态代理作用是什么?

    Java 动态代理作用是什么?   1 条评论 分享   默认排序按时间排序 19 个回答 133赞同反对,不会显示你的姓名 Intopass 程序员,近期沉迷于动漫ING 133 人赞同 ① 首先你 ...

  5. java动态代理原理

    我们经常会用到Java的动态代理技术, 虽然会使用, 但是自己对其中的原理却不是很了解.比如代理对象是如何产生的, InvocationHandler的invoke方法是如何调用的?今天就来深究下Ja ...

  6. java 动态代理示例,带主要注释

    Java proxy是基于反射,仅仅支持基于接口的动态代理. java 动态代理是一切架构的基础,必须了解. 废话少说,先上代码获得感性认识. 示例代码有主要注释. 接口: public interf ...

  7. java动态代理浅析

    最近在公司看到了mybatis与spring整合中MapperScannerConfigurer的使用,该类通过反向代理自动生成基于接口的动态代理类. 于是想起了java的动态代理,然后就有了这篇文章 ...

  8. Java 动态代理

    被代理的接口特点: 1. 不能有重复的接口,以避免动态代理类代码生成时的编译错误. 2. 这些接口对于类装载器必须可见,否则类装载器将无法链接它们,将会导致类定义失败. 3. 需被代理的所有非 pub ...

  9. [转]java动态代理(JDK和cglib)

    转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理 ...

  10. java动态代理模式

    java动态代理机制详解 Spring的核心AOP的原理就是java的动态代理机制. 在java的动态代理机制中,有两个重要的类或接口: 1.InvocationHandler(Interface): ...

随机推荐

  1. Oracle数据库常用的sql语句

    1. select * from emp; 2. select empno, ename, job from emp; 3. select empno 编号, ename 姓名, job 工作 fro ...

  2. java并发里的一些基础概念

    转载自:https://my.oschina.net/hosee/blog/597934: 摘要: 本系列基于炼数成金课程,为了更好的学习,做了系列的记录. 本文主要介绍 1.高并发的概念,为以后系列 ...

  3. 微信小程序 js结构

    // pages/index/index.js Page({ /** * 页面的初始数据 */ data: { }, /** * 生命周期函数--监听页面加载 */ onLoad: function ...

  4. Word图片上传控件卸载教程-Xproer.WordPaster

      卸载教程:      卸载控件-IE          Windows XP          Windows 7(x86)          Windows 7(x64)      卸载控件-C ...

  5. 冬瓜头答疑:磁盘阵列内部FC-AL的性能问题

    冬瓜头答疑:磁盘阵列内部FC-AL的性能问题 作者:冬瓜头出处:IT专家网2009-08-03 09:59   问: 大多数磁盘阵列都是通过两个控制器后端的端口,组成1/2/4条FC-AL环,来连接所 ...

  6. kepware http接口 c语言(libcrul)开发

    列出所有变量 CURL *hnd = curl_easy_init(); curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET"); ...

  7. SPRING框架中ModelAndView、Model、ModelMap区别及详细分析

    转载内容:http://www.cnblogs.com/google4y/p/3421017.html 1. Model Model 是一个接口, 其实现类为ExtendedModelMap,继承了M ...

  8. hdu 4901 划分序列使异或和==且和

    http://acm.hdu.edu.cn/showproblem.php?pid=4901 给定一个序列,要求选出两个集合,S和T,要求S中选中的元素的下标都要小于T中元素的下标.并且说S中元素的异 ...

  9. Python自动化开发 - 面向对象(二)

    本节内容 1.isinstance(obj,cls)和issubclass(sub,super) 2.反射 3.__setattr__,__delattr__,__getattr__ 一. isins ...

  10. [正则表达式] PHP 中使用正则表达式收集(2016/01/08 - )

    // 1. 过滤字符串中src 属性为空的img 标签 $filterBack = preg_replace("/<img[^<>]*src\=[\'\"][\' ...