动态代理
- 特点: 字节码随用随创建,随用随加载
- 作用: 不修改源码的基础下,使方法增强
- 分类:
- 基于接口的动态代理
- 基于子类的动态代理
基于接口的动态代理
- 涉及的类:
Proxy
- 提供者: JDK
- 如何创建代理对象
- 使用
Proxy
类中的newProxyInstance
方法
- 使用
- 创建代理对象的要求
- 被代理对象最少实现一个接口,如果没有则不能使用
newProxyInstance
方法的参数:ClassLoader
: 类加载器- 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器(就是你要代理谁,就写谁的类加载器)【固定写法】
Class[]
: 字节码数组- 它是用于让代理对象和被代理对象有相同方法【固定写法】
InvocationHandler
: 用于提供增强的代码- 它是让我们写如何代理,一般都是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的
- 此接口的实现类是谁用谁写
基于接口动态代理的一个例子
当我们的类不实现接口的时候,是不能用动态代理的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27public static void main(String[] args) {
final Producer producer = new Producer();
IProducer proxyProduce = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() {
/**
* 作用:执行被代理的对象的任何接口方法都会经过该方法
* 方法参数的含义
* @param proxy
* @param method 当前执行的方法
* @param args 当前执行的方法所需的参数
* @return 和被代理对象方法有相同的返回值
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 提供增强的代码
Object returnValue = null;
// 1.获取方法执行的参数
Float money = (Float) args[0];
// 2.判断当前方法是不是销售
if ("saleProduct".equals(method.getName())){
returnValue = method.invoke(producer, money*0.8f);
}
return returnValue;
}
});
proxyProduce.saleProduct(10000);
}
基于子类的动态代理
需要第三方JAR包的支持1
2
3
4
5<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>
- 涉及的类:
Enhancer
- 提供者: 第三方类库cglib
- 如何创建代理对象
- 使用
Enhancer
类中的create
方法
- 使用
- 创建代理对象的要求
- 被代理类不能是最终类(最终类就不能创建子类了)
create
方法的参数:Class
: 字节码- 用于指定被代理对象的字节码
Callback
: 用于提供增强的代码- 它是让我们写如何代理,一般都是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的
- 此接口的实现类是谁用谁写
- 我们一般写的都是该接口的子接口实现类:
MethodInterceptor
代码实现
1 | public static void main(String[] args) { |
通过动态代理改善代码
即实现了简化开发,又实现了事务控制1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41/**
* 用于创建Service代理对象的工厂
*/
public class BeanFactory {
private AccountService accountService;
private TransactionManager txManager;
public void setTxManager(TransactionManager txManager) {
this.txManager = txManager;
}
public final void setAccountService(AccountService accountService) {
this.accountService = accountService;
}
public AccountService getAccountService(){
return (AccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object rtValue = null;
try {
// 1.开启事务
txManager.beginTransaction();
// 2.执行操作
rtValue = method.invoke(accountService, args);
// 3.提交事务
txManager.commit();
// 4.返回结果
return rtValue;
} catch (Exception e){
// 5.回滚操作
txManager.rollback();
throw new RuntimeException(e);
} finally {
// 6.释放连接
txManager.release();
}
}
});
}
}
AccountServiceImpl1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public void transfer(String sourceName, String targetName, Integer money) {
System.out.println("transfer");
Account source = accountDao.findAccountByName(sourceName);
Account target = accountDao.findAccountByName(targetName);
source.setMoney(source.getMoney() - money);
target.setMoney(target.getMoney() + money);
accountDao.updateAccount(source);
// int i = 1/0;
accountDao.updateAccount(target);
}
测试类1
2
3
4
5
6
7
8
9
10
11
12@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountServiceTest {
@Autowired
@Qualifier("proxyAccountService")
private AccountService accountService;
@Test
public void testTransfer() {
accountService.transfer("aaa", "bbb", 100);
}
}
bean.xml1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置代理的Service-->
<bean id="proxyAccountService" factory-bean="beanFactory" factory-method="getAccountService"></bean>
<!--配置BeanFactory-->
<bean id="beanFactory" class="com.xushui.factory.BeanFactory">
<property name="txManager" ref="transactionManager"></property>
<property name="accountService" ref="accountService"></property>
</bean>
<bean id="accountService" class="com.xushui.service.Impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
...