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学习(五):动态代理的两种实现方式(全网最容易懂)相关推荐

  1. spring中AOP动态代理的两种方式

    AOP动态代理的两种方式 Spring AOP动态代理的方式(spring的AOP默认是JDK Proxy) 浅谈这两种动态代理 JDK的动态代理,需要有实现接口 动态代理--JDK Proxy ⚫ ...

  2. SpringAop动态代理的两种实现方式

    Spring的面向切面编程也是基于动态代理来实现的 静态代理:也就是自己手动创建的代理对象 动态代理:也就是在程序运行中通过配置参生的 那么Spring的AOP也就是面向切面编程,就是基于动态代理来实 ...

  3. 动态代理的两种实现方式

    1.动态代理介绍 动态代理:在不改变目标对象方法的情况下对方法进行增强 组成: 被代理对象:真实的对象 代理对象:内存中的对象 要求:代理对象必须和被代理对象实现相同的接口 代理的实现方式有两种:(1 ...

  4. Java中动态代理的两种方式JDK动态代理和cglib动态代理以及区别

    视频功能审核通过了,可以看视频啦!记得点关注啊~ 注意:因为网络原因,视频前一两分钟可能会比较模糊,过一会儿就好了 记得点关注啊,视频里的wx二维码失效了,wx搜索:"聊5毛钱的java&q ...

  5. Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理

    Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理 代理模式 JDK动态代理 CGLIB动态代理 代理模式 代理模式是23种设计模式的一种,指一个对象A通过持有另一个对象B,可以具有B ...

  6. Java动态代理的两种实现方法

    转载自 http://blog.csdn.net/HEYUTAO007/article/details/49738887 AOP的拦截功能是由java中的动态代理来实现的.说白了,就是在目标类的基础上 ...

  7. 动态代理的两种方式_动态代理是基于什么原理?

    代理模式 给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问. 什么是动态代理 运行时动态生成代理类. 动态代理我们需要些什么 1.业务接口(Interface) 业务的抽象表示. 2.业务 ...

  8. spring学习--AOP--JDK动态代理

    JDK动态代理 使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象 newProxyInstance 方法如下: public static Object newProxyInstan ...

  9. C语言动态数组的两种定义方式

      动态内存分配具有非常多的好处,可以最大化的节约内存空间的大小.本文将通过两种方式来实现C语言中内存的动态分配,希望你看完本文后能有所收获. 一.直接对数组大小进行输入 在C99标准中C语言数组已支 ...

  10. Java实现动态代理的两种方式

    http://m.blog.csdn.net/article/details?id=49738887

最新文章

  1. GPUImage滤镜之锐化
  2. eclipse Indigo Helios Galileo几种版本的意思
  3. 快慢指针____函数将字符串中的字符'*'移到串的前部分,前面的非'*'字符后移
  4. OpenCV扫描图像,查找表和时间测量
  5. test1 3-15 模拟赛1
  6. JavaWeb关于工程运行的笔记
  7. JSON 和 JS 对象互转
  8. DCMTK3.6.0(MD支持库)安装说明-无图版
  9. n160ii打印机查看ip地址_喷墨打印机自动清洁打印头方法你知道几个?
  10. Springboot+网上投资借贷中介服务 毕业设计-附源码221506
  11. 带宽、特征频率、截止频率、-3dB什么意思
  12. php企业微信获取userid,企业微信端项目登陆、获取用户信息流程等
  13. 【IOI2018】组合动作
  14. 信号完整性(SI)电源完整性(PI)学习笔记(二十六)S参数在信号完整性中的应用(一)
  15. Arithmetic Progressions
  16. 服务器flash卡的作用是什么原因,直播卡顿原因详解及优化
  17. 头像上传(限制大小,格式,尺寸)
  18. HDTV入门扫盲篇HDTV入门
  19. java程序员必看书籍
  20. INVE主网砸金蛋小游戏玩法

热门文章

  1. wampserver php 目录,小常识-WAMPServer自定义根目录
  2. 如何获取小程序页面路径
  3. 最近发现的一个c# winform的一个很好用很强大的excel控件 reogrid控件
  4. Vue 自定义项目的创建以及配置
  5. vue后台管理框架(iview + vue)
  6. 矩阵卷积、矩阵相乘以及频域相乘之间的关系
  7. python代码美化工具
  8. 信息化案例:国家电投
  9. 锐浪报表数据源access_C# 锐浪报表 示例源码
  10. 圣思园【深入JVM】笔记-第一课-论学习方法