java代理模式之JDK动态代理

news/2024/8/26 21:15:10 标签: 代理模式

目录

什么是动态代理?

动态代理的两种方式?

jdk动态代理;

cglib静态代理

为什么需要代理?

1、原有功能增强

2、降低耦合

JDK动态代理代码实例:

实体类:

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

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

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

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

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


什么是动态代理?

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

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

动态代理的两种方式?

  • jdk动态代理;

  • cglib静态代理

为什么需要代理?

1、原有功能增强

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

2、降低耦合

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

JDK动态代理代码实例:

实体类:

/**
 * 实体类
 * 账户表的实体类
 * 序列化
 * 反序列化
 */
public class Account implements Serializable{

    //id
    private 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;
    }

    @Override
    public 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{


//    @Override
    public 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());
        //执行sql
        int 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
     */
//    @Override
    public 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,按要求(根据三个参数)返回一个代理对象proxy
        Object proxy=Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() {

            /**
             * 调用代理对象AccountServiceImpl的方法,invoke方法就会去执行
             */
//            @Override
            public 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 {

		// 从当前线程中获取Connection
		Connection 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 {
			// 从当前线程中获取Connection
			Connection conn = threadLocal.get();
			if (conn != null) {
				// 回滚事务
				conn.rollback();
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * @Method: commit
	 * @Description:提交事务
	 * @Anthor:
	 */
	public static void commit() {
		try {
			// 从当前线程中获取Connection
			Connection conn = threadLocal.get();
			if (conn != null) {

				// 提交事务
				conn.commit();

			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * @Method: close
	 * @Description:关闭数据库连接(注意,并不是真的关闭,而是把连接还给数据库连接池)
	 * @Anthor:
	 *
	 */
	public static void close() {
		try {
			// 从当前线程中获取Connection
			Connection conn = threadLocal.get();
			if (conn != null) {
				conn.close();
				// 解除当前线程上绑定conn
				threadLocal.remove();
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * @Method: getDataSource
	 * @Description: 获取数据源
	 * @Anthor:
	 * @return DataSource
	 */
	public static DataSource getDataSource() {
		// 从数据源中获取数据库连接
		return ds;
	}

}

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

public class TestDemo {

    @Test
    public 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);
    }
}


http://www.niftyadmin.cn/n/5558463.html

相关文章

docker快速安装(环境CentOS7)

1. 查看自己的Linux系统 cat /etc/redhat-release 2. 安装依赖插件 yum -y install gcc yum -y install gcc-c yum install -y yum-utils yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo yum makecache fast yum -y insta…

影响转化率的多元因素分析及定制开发AI智能名片S2B2C商城系统小程序的应用案例

摘要&#xff1a;在互联网时代&#xff0c;转化率是衡量营销活动成功与否的关键指标。本文首先分析了影响转化率的多种因素&#xff0c;包括活动页面的设计、活动的限时性、主题文案的吸引力、从众心理的运用&#xff0c;以及最核心的产品质量与优惠力度。接着&#xff0c;本文…

解析 Mira :基于 Web3,让先进的 AI 技术易于访问和使用

“Mira 平台正在以 Web3 的方式解决当前 AI 开发面临的复杂性问题&#xff0c;同时保护 AI 贡献者的权益&#xff0c;让他们可以自主拥有并货币化自己的模型、数据和应用&#xff0c;以使先进的 AI 技术更加易于访问和使用。” AI 代表着一种先进的生产力&#xff0c;它通过深…

flask渲染页码

在 Flask 框架中,如果你想实现分页功能并渲染页码到你的 HTML 页面,你可以使用 Flask-SQLAlchemy 和 Flask-Paginate 这样的扩展来简化这个过程。下面用一个简单的例子来说明如何在 Flask 应用中实现分页和渲染页码。 首先,确保你已经安装了 Flask-SQLAlchemy 和 Flask-Pag…

迈克尔的44岁:时间的感悟与人生的智慧

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

操作系统真象还原:实现文件写入

14.7 实现文件写入 这是一个网站有所有小节的代码实现&#xff0c;同时也包含了Bochs等文件 本节要实现的 sys_write 是系统调用 write 的内核实现&#xff0c;咱们之前的 write 是个简易版&#xff0c;它是为了临时完成输出打印的功能&#xff0c;不支持文件描述符。如今要让…

前端面试题日常练-day92 【Less】

题目 希望这些选择题能够帮助您进行前端面试的准备&#xff0c;答案在文末 在Less中&#xff0c;以下哪个符号用于定义变量&#xff1f; a) $ b) # c) d) & Less中的Extend是用来做什么的&#xff1f; a) 继承样式 b) 创建循环 c) 定义变量 d) 处理函数 在Less中&#…

独角数卡(自动发卡系统)开源自动化售货最新2.0.6

独角数卡&#xff08;自动售货系统&#xff09;是一款基于Laravel框架的开源站长自动化售货解决方案。它具有高效、稳定和快速的特点&#xff0c;支持自定义前端模板、国际化多语言包以及长期技术更新支持。然而&#xff0c;该程序对新手来说有一定的上手难度&#xff0c;需要具…