当前位置: 首页 > news >正文

java代理模式之JDK动态代理

目录

什么是动态代理?

动态代理的两种方式?

jdk动态代理;

cglib静态代理

为什么需要代理?

1、原有功能增强

2、降低耦合

JDK动态代理代码实例:

实体类:

持久层接口+实现类(使用jdbc进行数据库操作)

业务层接口+实现类(调用持久层,仅书写业务逻辑,不进行其他操作,如添加事物处理等)

代理类:代理的是AccountService接口 获取业务层接口的代理对象,增强后返回

工具类:提供一些工具方法,如建立连接池,创建数据库,进行事物操作的方法等

测试类:直接调用代理类进行操作


什么是动态代理?

动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。

可以通过调用代理对象来实现对目标对象的调用。

动态代理的两种方式?

  • jdk动态代理;

  • cglib静态代理

为什么需要代理?

1、原有功能增强

举例来说,当前类的代码只能满足一些基本的功能,而这些功能满足不了新需求,但又不能改动以前的代码,这时就用代理模式。通过代理类,扩展原有类的功能,客户端访问的入口只是从目标对象切换到代理对象而已;

2、降低耦合

使用代理类,可以在不对原来类修改的基础上,进行相关功能的扩展

JDK动态代理代码实例:

实体类:

/*** 实体类* 账户表的实体类* 序列化* 反序列化*/
public class Account implements Serializable{//idprivate Integer id;//名称private String name;//钱 金额private Double money;public Account() {}public Account(Integer id, String name, Double money) {this.id = id;this.name = name;this.money = money;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Double getMoney() {return money;}public void setMoney(Double money) {this.money = money;}@Overridepublic String toString() {return "Account{" +"id=" + id +", name='" + name + '\'' +", money=" + money +'}';}
}

持久层接口+实现类(使用jdbc进行数据库操作)

/*** 持久层接口* 面向接口开发*/
public interface AccountDao {//保存账户public void saveAll(Account account) throws SQLException;
}
/*** 持久层接口实现类* 面向接口开发*/
public class AccountDaoImpl implements AccountDao{//    @Overridepublic void saveAll(Account account) throws SQLException {//jdbc//使用工具类  减少加载驱动 直接获取连接System.out.println("持久层:保存账户...");// 把数据存储到数据库中// 先获取到连接Connection connection = TxUtils.getConnection();//编写sql// 编写sql语句String sql = "insert into account values (null,?,?)";//获取执行对象stmt  prepareStatement(sql注入)  Statement(不可以防止)PreparedStatement statement = connection.prepareStatement(sql);// 设置值statement.setString(1,account.getName());statement.setDouble(2,account.getMoney());//执行sqlint i = statement.executeUpdate();//关闭资源statement.close();}
}

业务层接口+实现类(调用持久层,仅书写业务逻辑,不进行其他操作,如添加事物处理等)

/*** 账户的接口*/
public interface AccountService {//保存账户public void saveAll(Account account1,Account account2) throws SQLException;
}
/*** 账户业务层实现类* 目的:实现新增账户* 演示事务*/
public class AccountServiceImpl implements  AccountService{private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}/*** 实现保存* @param account1* @param account2* @throws SQLException*/
//    @Overridepublic void saveAll(Account account1, Account account2) throws SQLException {accountDao.saveAll(account1);int i=5/0;accountDao.saveAll(account2);}
}

代理类:代理的是AccountService接口 获取业务层接口的代理对象,增强后返回

因为jdk动态代理是面向接口的

/*** 代理类* 使用动态代理JDK   面向接口* 传入目标对象,生成该对象的代理对象,返回。对目标对象的方法进行增强* Proxy java 反射*/
public class JdkProxy {/*** 获取代理对象并返回,增强目标对象的方法* @param accountService* @return*/public static Object getProxy(final AccountService accountService){//通过java反射包里提供的Proxy的类的api方法newProxyInstance,按要求(根据三个参数)返回一个代理对象proxyObject proxy=Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() {/*** 调用代理对象AccountServiceImpl的方法,invoke方法就会去执行*/
//            @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//创建一个空的结果集对象Object result=null;try {// 开启事务TxUtils.startTransaction();//执行目标对象的实际业务// 对象目标对象的方法进行增强result = method.invoke(accountService, args);// 提交事务TxUtils.commit();}catch (Exception e){e.printStackTrace();//回滚事务TxUtils.rollback();}finally {TxUtils.close();}return result;//返回代理对象}});return proxy;}
}

工具类:提供一些工具方法,如建立连接池,创建数据库,进行事物操作的方法等

*** 事务的工具类  数据库连接的工具类*/
public class TxUtils {//类属性 连接池对象private static DruidDataSource ds = null;// 使用ThreadLocal存储当前线程中的Connection对象private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();// 在静态代码块中创建数据库连接池static {try {// 通过代码创建druid数据库连接池ds = new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql:///spring_db?useUnicode=true&characterEncoding=utf8");ds.setUsername("root");ds.setPassword("root");} catch (Exception e) {throw new ExceptionInInitializerError(e);}}/*** @Method: getConnection* @Description: 从数据源中获取数据库连接* @Anthor:* @return Connection* @throws SQLException*/public static Connection getConnection() throws SQLException {// 从当前线程中获取ConnectionConnection conn = threadLocal.get();if (conn == null) {// 从数据源中获取数据库连接conn = getDataSource().getConnection();// 将conn绑定到当前线程threadLocal.set(conn);}return conn;}/*** @Method: startTransaction* @Description: 开启事务* @Anthor:**/public static void startTransaction() {try {Connection conn = threadLocal.get();if (conn == null) {conn = getConnection();// 把 conn绑定到当前线程上threadLocal.set(conn);}// 开启事务conn.setAutoCommit(false);} catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: rollback* @Description:回滚事务* @Anthor:*/public static void rollback() {try {// 从当前线程中获取ConnectionConnection conn = threadLocal.get();if (conn != null) {// 回滚事务conn.rollback();}} catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: commit* @Description:提交事务* @Anthor:*/public static void commit() {try {// 从当前线程中获取ConnectionConnection conn = threadLocal.get();if (conn != null) {// 提交事务conn.commit();}} catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: close* @Description:关闭数据库连接(注意,并不是真的关闭,而是把连接还给数据库连接池)* @Anthor:**/public static void close() {try {// 从当前线程中获取ConnectionConnection conn = threadLocal.get();if (conn != null) {conn.close();// 解除当前线程上绑定connthreadLocal.remove();}} catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: getDataSource* @Description: 获取数据源* @Anthor:* @return DataSource*/public static DataSource getDataSource() {// 从数据源中获取数据库连接return ds;}}

测试类:直接调用代理类进行操作

public class TestDemo {@Testpublic void run() throws SQLException {ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");AccountService service = (AccountService) ac.getBean("service");AccountService proxy = (AccountService) JdkProxy.getProxy(service);Account account1=new Account();account1.setName("张三0716");account1.setMoney(5000.00);Account account2=new Account();account2.setName("李四0716");account2.setMoney(9000.00);proxy.saveAll(account1,account2);}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Bigdata-Docker构建大数据学习开发环境
  • git回退分支版本git reset --hard HEAD
  • Beelzebub过程记录及工具集
  • PG大会周五于杭州举办;Pika发布4.0;阿里云MySQL上线Zero-ETL集成能力
  • vue3前端页面下载excel模版
  • c#中的字符串方法
  • Linux C++ 056-设计模式之迭代器模式
  • 【D3.js in Action 3 精译】1.3 D3 视角下的数据可视化最佳实践(下)
  • opencv—常用函数学习_“干货“_9
  • 常见的排序算法,复杂度
  • jail子系统里升级Ubuntu focal到jammy
  • XML 验证器:确保数据完整性和准确性的关键工具
  • 如何查看极狐GitLab Helm Chart?
  • 用Pytorch实现线性回归(Linear Regression with Pytorch)
  • 基于luckysheet实现在线电子表格和Excel在线预览
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • Android组件 - 收藏集 - 掘金
  • CentOS7 安装JDK
  • CSS魔法堂:Absolute Positioning就这个样
  • Django 博客开发教程 8 - 博客文章详情页
  • js继承的实现方法
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • python_bomb----数据类型总结
  • Sass 快速入门教程
  • Spring Boot快速入门(一):Hello Spring Boot
  • vue脚手架vue-cli
  • 阿里云购买磁盘后挂载
  • 排序(1):冒泡排序
  • 算法-插入排序
  • 微服务入门【系列视频课程】
  • Linux权限管理(week1_day5)--技术流ken
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • 阿里云API、SDK和CLI应用实践方案
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • $NOIp2018$劝退记
  • (1)(1.13) SiK无线电高级配置(六)
  • (C语言)共用体union的用法举例
  • (苍穹外卖)day03菜品管理
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (翻译)terry crowley: 写给程序员
  • (分布式缓存)Redis分片集群
  • (六)软件测试分工
  • (排序详解之 堆排序)
  • (全注解开发)学习Spring-MVC的第三天
  • (三分钟)速览传统边缘检测算子
  • (十六)Flask之蓝图
  • (算法)Game
  • (五十)第 7 章 图(有向图的十字链表存储)
  • (转载)Google Chrome调试JS
  • (转载)OpenStack Hacker养成指南
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .Net CoreRabbitMQ消息存储可靠机制
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)