Spring学习(五):动态代理的两种实现方式(全网最容易懂)
Spring学习(五):动态代理的两种实现方式(全网最容易懂)
前言
要学习SpringAOP之前,肯定要弄清楚什么是动态代理,动态代理是怎样实现的,以及动态代理能解决什么问题。
一、什么是动态代理
1、字面意思,代理就是代替别人去做一些事情,如线下店代替工厂去卖电脑、代理工厂做售后工作,线下店就是代理商,从卖给工厂的获得的钱提取分成就是增强的方法。
2、Java中就是在不改变别别的类,对类做增强处理,如打印日志、事物的控制,权限的管理,后续我们都会介绍。
二、两种实现动态代理的方法
1、基于JDK的动态代理
基于接口的动态代理,用到的类是Proxy的newProxyInstance静态方法创建,要求被代理对象至少实现一个接口,如果没有,则不能创建代理对象。
2、基于cglib的动态代理
要导入cglib第三方库,使用的类是Enhancer的create静态方法创建,要求被代理类不能是最终类,即不能用final修饰,如String类。
三、代码演示
1、首先创建一个IProduct接口,并创建被代理类,实现这个接口
IProduct
public interface IProduct {String sell(Float money);void afterSell();
}
Product
public class Product implements IProduct {@Overridepublic String sell(Float money) {System.out.println("代理员交给工厂:"+money);return "aaa";}@Overridepublic void afterSell() {System.out.println("代理员做售后。。");}
}
2、通过JDK来实现动态代理,创建一个消费者Consumer
这里我们直接通过匿名内部类来实现,当然不是必须的
Consumer类
public class Consumer {public static void main(String[] args) {// 创建一个被代理对象final Product product = new Product();// 创建一个代理对象,并在InvocationHandler的invoke方法里面,对被代理类的方法做增强IProduct proxyProduct = (IProduct) Proxy.newProxyInstance(product.getClass().getClassLoader(), product.getClass().getInterfaces(), new InvocationHandler() {// 实现具体的增强操作 @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 获取方法在运行中可能产生的返回值Object returnValue = null;Float money = (Float) args[0];if("sell".equals(method.getName())){// 执行具体的方法returnValue = method.invoke(product, money*0.8F);}return returnValue;}});System.out.println(proxyProduct.sell(1000F));}
}
代码分析
1、Proxy.newProxyInstance的三个参数
IProduct proxyProduct = (IProduct) Proxy.newProxyInstance(product.getClass().getClassLoader(), product.getClass().getInterfaces(), new InvocationHandler() {}
ClassLoader loader
获取被代理类的类加载器。Class<?>[] interfaces
获取被代理类的实现接口的数组。InvocationHandler h
在invok方法中对方法做增强处理。
2、invoke方法的三个参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {}
Object proxy
当前代理对象Method method
当前方法Object[] args
方法传递的参数
3、通过cglib来实现动态代理,创建一个消费者Consumer
public class Consumer {public static void main(final String[] args) {// 创建一个被代理对象,这里要求必须是finalfinal Product product = new Product();Product proxyProduct =(Product) Enhancer.create(product.getClass(), new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {Float money = (Float) objects[0];Object returnValue = null;if("sell".equals(method.getName())){returnValue = method.invoke(product, 0.8f * money);}return returnValue;}});System.out.println(proxyProduct.sell(1000f));}
}
代码分析
1、Enhancer.create的2个参数
Product proxyProduct =(Product) Enhancer.create(product.getClass(), new MethodInterceptor() {}
Class type
被代理类的class文件Callback callback
一个Callback接口,我们通常使用MethodInterceptor
接口,继承了Callback接口
2、intercept方法的参数
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {}
Method method
当前方法Object[] objects
方法用到的参数数组
4、测试结果
代理员交给工厂:800.0
aaa
代理商收取了200块提成。
四、结合BeanFactory创建Bean的方式来控制事务
学完动态代理,可以结合BeanFactory创建Bean的方式来控制事务
1、改造事务分析
Spring学习(四):事务的学习之银行转账案例
原来的事务控制我们是写在Service层,现在我们要把重复代码抽取出来,统一交给代理对象去管理事务。
原Service代码
@Service("accountService")
public class AccountServiceImpl implements IAccountService {@AutowiredTransactionManager transactionManager;@AutowiredIAccountDao accountDao;@Autowiredprivate ConnectionUtils connectionUtils;@Overridepublic void updateAccount(Account account) {try {transactionManager.beginTransaction();accountDao.updateAccount(account);int a = 1/0; // 模拟业务层出错transactionManager.commitTransaction();}catch (Exception e){transactionManager.rollbackTransaction();e.printStackTrace();}finally {transactionManager.release();}}
}
现在我们只留一行代码
accountDao.updateAccount(account);
2、代码编写思路分析
- 创建一个BeanFactory,里面注入一个AccountService。
- 在get方法中返回一个代理对象。
- 选择一种动态代理的实现方法,编写代理详细实现代码。
- 配置bean.xml配置文件
3、代码的实现
BeanFactory类
public class BeanFactory {@Autowired/*** 由于配置文件有2个AccountService实现类的bean配置,所以要指定beanId才可以自动注入* proxyAccountService、accountService*/@Qualifier("accountService")private IAccountService iAccountService;@AutowiredTransactionManager transactionManager;// 通过JDK动态代理实现public IAccountService getAccountService() {IAccountService proxyIaccountService = (IAccountService) Proxy.newProxyInstance(iAccountService.getClass().getClassLoader(), iAccountService.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object returnValue = null;try {transactionManager.beginTransaction();System.out.println("开启事务。。。");System.out.println("执行【"+method.getName()+"】方法。。。");returnValue = method.invoke(iAccountService, args);System.out.println(5/0);transactionManager.commitTransaction();System.out.println("COMMIT事务。。。");}catch (Exception e){System.out.println("ROLLBACK事务。。。");transactionManager.rollbackTransaction();e.printStackTrace();}finally {transactionManager.release();}return returnValue;}});return proxyIaccountService;}// 通过Cglib动态代理实现public IAccountService getAccountServiceByCglib() {IAccountService proxyAccountServiceByCglib = (IAccountService) Enhancer.create(IAccountService.class, new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {Object returnValue = null;try {transactionManager.beginTransaction();System.out.println("开启事务。。。");System.out.println("执行【"+method.getName()+"】方法。。。");returnValue = method.invoke(iAccountService, objects);System.out.println(5/0);transactionManager.commitTransaction();System.out.println("COMMIT事务。。。");}catch (Exception e){System.out.println("ROLLBACK事务。。。");transactionManager.rollbackTransaction();e.printStackTrace();}finally {transactionManager.release();}return returnValue; }});return proxyAccountServiceByCglib;}public void setIAccountService(IAccountService iAccountService) {this.iAccountService = iAccountService;}
}
xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!--找到对应的XML头,和打开包扫描--><context:component-scan base-package="com"/><bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"><constructor-arg name="ds" ref="dataSource"></constructor-arg></bean><!--配置数据源--><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="com.mysql.jdbc.Driver" /><property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test" /><property name="user" value="root"/><property name="password" value="123456" /></bean><bean id="connectionUtils" class="com.utils.ConnectionUtils"><property name="dataSource" ref="dataSource" /></bean><bean id="transationManager" class="com.utils.TransactionManager"><property name="connectionUtils" ref="connectionUtils" /></bean><!-- 配置BeanFactory类,用工厂创建我们的代理AccountService --><bean id="beanFactory" class="com.utils.BeanFactory"></bean><!-- 通过JDK动态代理实现 --><bean id="proxyAccountService" factory-bean="beanFactory" factory-method="getAccountService"></bean><!-- 通过Cglib动态代理实现 --><bean id="proxyAccountServiceByCglib" factory-bean="beanFactory" factory-method="getAccountServiceByCglib"></bean></beans>
测试类
public void testFindAccountAll(){ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");IAccountService accountService = (IAccountService) context.getBean("proxyAccountService");Account account = new Account();account.setId(1);account.setMoney(500D);account.setName("aaa");accountService.updateAccount(account);
}
可以看到代理类实现了事务,当代码报错,数据正常回滚了。
五、总结
1、JDK动态代理,自带的,方便使用,但是要要求必须实现接口,有一定的约束。
2、cglib,需要导入第三方jar包,使用的时候没有什么约束。
3、SpringAOP以上2种方法都用到了。
4、学完动态代理,可以结合BeanFactory创建Bean的方式来控制事务。
Spring学习(五):动态代理的两种实现方式(全网最容易懂)相关推荐
- spring中AOP动态代理的两种方式
AOP动态代理的两种方式 Spring AOP动态代理的方式(spring的AOP默认是JDK Proxy) 浅谈这两种动态代理 JDK的动态代理,需要有实现接口 动态代理--JDK Proxy ⚫ ...
- SpringAop动态代理的两种实现方式
Spring的面向切面编程也是基于动态代理来实现的 静态代理:也就是自己手动创建的代理对象 动态代理:也就是在程序运行中通过配置参生的 那么Spring的AOP也就是面向切面编程,就是基于动态代理来实 ...
- 动态代理的两种实现方式
1.动态代理介绍 动态代理:在不改变目标对象方法的情况下对方法进行增强 组成: 被代理对象:真实的对象 代理对象:内存中的对象 要求:代理对象必须和被代理对象实现相同的接口 代理的实现方式有两种:(1 ...
- Java中动态代理的两种方式JDK动态代理和cglib动态代理以及区别
视频功能审核通过了,可以看视频啦!记得点关注啊~ 注意:因为网络原因,视频前一两分钟可能会比较模糊,过一会儿就好了 记得点关注啊,视频里的wx二维码失效了,wx搜索:"聊5毛钱的java&q ...
- Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理
Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理 代理模式 JDK动态代理 CGLIB动态代理 代理模式 代理模式是23种设计模式的一种,指一个对象A通过持有另一个对象B,可以具有B ...
- Java动态代理的两种实现方法
转载自 http://blog.csdn.net/HEYUTAO007/article/details/49738887 AOP的拦截功能是由java中的动态代理来实现的.说白了,就是在目标类的基础上 ...
- 动态代理的两种方式_动态代理是基于什么原理?
代理模式 给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问. 什么是动态代理 运行时动态生成代理类. 动态代理我们需要些什么 1.业务接口(Interface) 业务的抽象表示. 2.业务 ...
- spring学习--AOP--JDK动态代理
JDK动态代理 使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象 newProxyInstance 方法如下: public static Object newProxyInstan ...
- C语言动态数组的两种定义方式
动态内存分配具有非常多的好处,可以最大化的节约内存空间的大小.本文将通过两种方式来实现C语言中内存的动态分配,希望你看完本文后能有所收获. 一.直接对数组大小进行输入 在C99标准中C语言数组已支 ...
- Java实现动态代理的两种方式
http://m.blog.csdn.net/article/details?id=49738887
最新文章
- GPUImage滤镜之锐化
- eclipse Indigo Helios Galileo几种版本的意思
- 快慢指针____函数将字符串中的字符'*'移到串的前部分,前面的非'*'字符后移
- OpenCV扫描图像,查找表和时间测量
- test1 3-15 模拟赛1
- JavaWeb关于工程运行的笔记
- JSON 和 JS 对象互转
- DCMTK3.6.0(MD支持库)安装说明-无图版
- n160ii打印机查看ip地址_喷墨打印机自动清洁打印头方法你知道几个?
- Springboot+网上投资借贷中介服务 毕业设计-附源码221506
- 带宽、特征频率、截止频率、-3dB什么意思
- php企业微信获取userid,企业微信端项目登陆、获取用户信息流程等
- 【IOI2018】组合动作
- 信号完整性(SI)电源完整性(PI)学习笔记(二十六)S参数在信号完整性中的应用(一)
- Arithmetic Progressions
- 服务器flash卡的作用是什么原因,直播卡顿原因详解及优化
- 头像上传(限制大小,格式,尺寸)
- HDTV入门扫盲篇HDTV入门
- java程序员必看书籍
- INVE主网砸金蛋小游戏玩法