基于动态代理(理解)反射机制
1 .什么是动态代理? 使用jdk反射机制创建对象的能力是在代理类中创建对象。 不需要创建类文件。 不需要写java文件。
动态:调用jdk提供的方法,在程序运行时创建代理类的对象。
jdk动态代理,需要接口,目标类需要实现接口,没有接口时需要使用cglib动态代理
2 .你知道动态代理能做什么吗? 可以在代理中扩展自己的功能代码,而不更改原始目标方法的功能。 程序开发中的意思。
例如,你所在的项目具有别人(公司其他部门、其他集团的人)写的功能。 可以使用。
-----GoNong.class,GoNong gn=new GoNong (,gn.print );
你发现这个功能,至今仍有缺点,不能完全满足我项目的需要。 gn.print ()运行后,我需要自己增加代码。
在代理上实现gn.print ()调用时,请添加自己的代码,而不是修改原始GoNong文件。
开发中也有这样的事情。 你有a类。 本来调用c类的方法来完成某个功能。 但是,c不让a呼叫。
不能调用a -----的方法。
在a和c中直接创建b代理,c让b访问。
访问a --访问--C
实际范例:登录,注册验证码,验证码是手机短信。
中国移动,联通可以发短信。
中国移动、联通有子公司或关联方,他们为社会提供短信发送功能
fzdlq项目发送邮件-----子公司或子公司-----中国移动、联通
3 .使用代理模式增强功能:在你原来的功能中增加了额外的功能。 新添加的功能称为功能扩展。 访问控制:代理类不允许目标访问。 例如,商家不让用户访问制造商。 4 .实现代理的方式1 .静态代理:代理类自己手工实现,自己创建表示代理类的java类。 同时,你代理的目标类已经确定。 特征)1)实现简单;2 )简单易懂。 缺点:在jzdhy项目中,如果目标类和代理类较多,则存在以下缺点:
1 )随着目标类的增加,代理类可能也需要加倍。 代理数量太多了。
2 )在jzdhy接口中添加或修改功能会影响许多实现系统、制造商系统和代理。 影响比较多。 例:模拟一个用户购买u盘的行为。 用户是客户端类
商家:代理,代理某个品牌的u盘。
制造商:目标类。
三方关系:用户(客户端)运营商;代理;制造商;目标)
商家和制造商正在销售u盘。 他们完成的功能一致,销售u盘。
实施步骤:
1 .创建一个定义如何销售u盘的接口,代表你的制造商和商家所做的。
2 .创建厂商类,实现一步界面
3 .做商家,是代理,需要实现一步界面。
4 .创建客户端类,调用商家的方法买一个u盘。
代理执行的功能:
1 .调用目标类中的方法
2 .增强权能
代码实现:
表示接口//功能的、制造商、商家要完成的功能public interface UsbSell { //定义方法参数amount:表示一次购买的数量,暂时以//返回值表示一个USB存储器的价格浮动销售(int amount; //其他方法可以有多个//void print (; (制造商) /目标类)金斯敦制造商不接受用户单独购买。 publicclassusbkingfactoryimplementsusbsell { @ overridepublicfloatsell (int amount ) { System.out.println目标类中的方法//后期通过amount,可以实现10000个、点击80,50000个75 return 85.0f等不同的价格; (}} //taobao是代理金斯敦u盘销售的公司。 publicclasstaobaoimplementsusbsell//声明代理商制造商具体是谁privateusbkingfactoryfactory=newusbkingfactory (); @ override//实现USB内存功能销售的publicfloatsell(intamount ) /向制造商发送订单,告知制造商已经买了USB内存,制造商将浮动价格=factory . //制造商的价格。 //商家需要涨价。 也就是说,代理商需要提高价格。 price=price 25; //扩展,代理类在完成目标类的方法调用后扩展了功能。 //调用目标类的方法后,您所做的所有其他功能都是增强的意思。 System.out.println (淘宝商,给你
返一个优惠券,或者红包"); //增加的价格 return price; }} 买家public class ShopMain { public static void main(String[] args) { //创建代理的商家taobao对象 TaoBao taoBao = new TaoBao(); //通过代理类,实现购买u盘,增加了优惠券,红包等等 float price = taoBao.sell(1); System.out.println("通过淘宝的商家,购买u盘单价:"+price); }} 2.动态代理在静态代理中目标类很多时候,可以使用动态代理,避免静态代理的缺点。
1)代理类数量可以很少,
2)jzdhy修改了接口中的方法时,不会影响代理类。
动态代理: 在程序执行过程中,使用jdk的反射机制,创建代理类对象, 并动态的指定要代理目标类。
换句话说: 动态代理是一种创建java对象的能力,让你不用创建TaoBao类,就能创建代理类对象。
在java中,要想创建对象:
创建类文件, java文件编译为class使用构造方法,创建类的对象。 动态代理的实现:jdk动态代理(理解): 使用java反射包中的类和接口实现动态代理的功能。
反射包 java.lang.reflect , 里面有三个类 : InvocationHandler , Method, Proxy.
cglib动态代理(了解): cglib是第三方的工具库, 创建代理对象。
cglib的原理是继承, cglib通过继承目标类,创建它的子类,在子类中
重写父类中同名的方法, 实现功能的修改。
因为cglib是继承,重写方法,所以要求目标类不能是final的, 方法也不能是final的。
cglib的要求目标类比较宽松, 只要能继承就可以了。cglib在很多的框架中使用,
比如 mybatis ,spring框架中都有使用。
反射包 java.lang.reflect , 里面有三个类 : InvocationHandler , Method, Proxy.
1)InvocationHandler 接口(调用处理器):就一个方法invoke()
invoke():表示代理对象要执行的功能代码。你的代理类要完成的功能就写在
invoke()方法中。
方法原型:
public Object invoke(Object proxy, Method method, Object[] args){}参数:
----Object proxy: jdk创建的代理对象,无需赋值。
----Method method: 目标类中的方法,jdk提供method对象的
----Object[] args: 目标类中方法的参数, jdk提供的。
(1) InvocationHandler 接口:表示你的代理要干什么。
怎么用:
(2) Method类:表示方法的, 确切的说就是目标类中的方法。
作用:通过Method可以执行某个目标类的方法,Method.invoke();
method.invoke(目标对象,方法的参数)
Object ret = method.invoke(service2, “jmdc”);
说明: method.invoke()就是用来执行目标方法的,等同于静态代理中的
//向厂家发送订单,告诉厂家,我买了u盘,厂家发货
float price = factory.sell(amount); //厂家的价格。
(3) Proxy类:核心的对象,创建代理对象。之前创建对象都是 new 类的构造方法()
现在我们是使用Proxy类的方法,代替new的使用。
作用是: 创建代理对象, 等同于静态代理中的TaoBao taoBao = new TaoBao();
参数: ClassLoader loader 类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader
类a , a.getCalss().getClassLoader(), 目标对象的类加载器Class<?>[] interfaces: 接口, 目标对象实现的接口,也是反射获取的。InvocationHandler h : 我们自己写的,代理类要完成的功能。
返回值:就是代理对象
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)实现动态代理的步骤:
创建接口,定义目标类要完成的功能创建目标类实现接口创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能1.调用目标方法
2.增强功能使用Proxy类的静态方法,创建代理对象。 并把返回值转为接口类型。
动态代理实际代码:(两个类)
public class ServiceFactory {public static Object getService(Object service){//这里返回的是代理类对象return new TransactionInvocationHandler(service).getProxy();}} import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import org.apache.ibatis.session.SqlSession;public class TransactionInvocationHandler implements InvocationHandler{private Object target;public TransactionInvocationHandler(Object target){this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {SqlSession session = null;Object obj = null;try{session = SqlSessionUtil.getSqlSession();obj = method.invoke(target, args);session.commit();}catch(Exception e){session.rollback();e.printStackTrace();//处理的是什么异常,继续往上抛什么异常throw e.getCause();}finally{SqlSessionUtil.myClose(session);}return obj;}public Object getProxy(){return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);}}