目录
什么是动态代理?
动态代理的两种方式?
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);
}
}