动态代理
# 动态代理(proxy)
动态代理:
特点: 字节码随用随创建,随用随加载
作用: 不修改源码的基础上对方法增强
分类:
1). 基于接口的动态代理
涉及的类: Proxy
提供者,JDK官方
2). 基于子类的动态代理
涉及的类: Enhancer
提供者: 第三方cglib库
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 1. 基于接口的动态代理
# 1. 概述
基于接口的动态代理
如何创建代理对象:
使用Proxy类中的newProxyInstance方法
创建代理对象的要求:
被代理的类最少实现一个接口,如果没有则不能使用
newProxyInstance方法的参数:
1). ClassLoader loader: 类加载器
它是用于加载代理对象字节码的.和被代理对象使用相同的类加载器.[固定写法]
2). Class<?>[] interfaces: 字节码数组
它是用于让代理对象和被代理对象有相同方法.[固定写法]
3). InvocationHandler h: 用于提供者增强的代码
它是让我们写如何代理.我们一般都是写一个该接口的实现类.通常情况下都是匿名内部类,但不是必须的.
此接口谁用谁写
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 2. 代码实现
- 生产者接口类
public interface ProducerInterface {
/**
* 销售
*
* @param money money
*/
public void saleProducer(float money);
/**
* 售后
*
* @param money money
*/
public void afterService(float money);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 生产者接口类实现
public class Producer implements ProducerInterface {
/**
* 销售
* @param money money
*/
public void saleProducer(float money) {
System.out.println("销售产品,并拿到钱" + money);
}
/**
* 售后
* @param money money
*/
public void afterService(float money) {
System.out.println("提供售后服务,并拿到钱" + money);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 消费者
public class Client {
public static void main(String[] args) {
// 1. 原来
// Producer producer = new Producer();
// producer.saleProducer(10000f);
// 2. 动态代理
final Producer producer = new Producer();
// 有反射
ProducerInterface proxyProducer = (ProducerInterface) Proxy.newProxyInstance(
// 1. 类加载器 [固定写法]
producer.getClass().getClassLoader(),
// 2. 字节码数组 [固定写法]
producer.getClass().getInterfaces(),
// 3. 用于提供者增强的代码 [匿名内部类]
new InvocationHandler() {
/**
* 作用: 执行被代理对象的任何接口方法都会经过该方法[拦截作用]
* @param proxy 代理对象
* @param method 当前执行的方法
* @param args 当前执行方法所需的参数
* @return 和被代理对象方法有相同的方绘制
* @throws Throwable 异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 提供增强的代码
Object returnValue = null;
// 1. 获取方法执行的参数
Float money = (Float) args[0];
// 2. 判断当前方法是不是销售
// 要代理方法名
String methodName = "saleProducer";
if (methodName.endsWith(method.getName())) {
returnValue = method.invoke(producer, money * 0.8f);
}
return returnValue;
}
});
proxyProducer.saleProducer(10000f);
}
}
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
42
43
44
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
42
43
44
# 2. 基于子类的动态代理
- 依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
1
2
3
4
5
2
3
4
5
# 1. 概述
动态代理:
特点: 字节码随用随创建,随用随加载
作用: 不修改源码的基础上对方法增强
分类:
1). 基于接口的动态代理
涉及的类: Proxy
提供者,JDK官方
2). 基于子类的动态代理
涉及的类: Enhancer
提供者: 第三方cglib库
基于子类的动态代理
如何创建代理对象:
使用Enhancer类中的create方法
创建代理对象的要求:
被代理的类不是最终类
create方法的参数:
1). class: 字节码
它是用于加载代理对象字节码的.和被代理对象使用相同的类加载器.[固定写法]
2). Class<?>[] interfaces: 字节码数组
它是用于让代理对象和被代理对象有相同方法.[固定写法]
3). InvocationHandler h: 用于提供者增强的代码
它是让我们写如何代理.我们一般都是写一个该接口的实现类.通常情况下都是匿名内部类,但不是必须的.
此接口谁用谁写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 2. 实现
- 生产者
public class Producer{
/**
* 销售
* @param money money
*/
public void saleProducer(float money) {
System.out.println("销售产品,并拿到钱" + money);
}
/**
* 售后
* @param money money
*/
public void afterService(float money) {
System.out.println("提供售后服务,并拿到钱" + money);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 消费者
public static void main(String[] args) {
// 1. 原来
// Producer producer = new Producer();
// producer.saleProducer(10000f);
// 2. 动态代理
final Producer producer = new Producer();
// 有反射
Producer cglibProducer = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
/**
* 执行被代理对象的任何方法都会经过该方法
* @param o 代理对象
* @param method 当前执行的方法
* @param objects 当前执行方法所需的参数
* @param methodProxy 当前执行方法的代理对象
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// 提供增强的代码
Object returnValue = null;
// 1. 获取方法执行的参数
Float money = (Float) objects[0];
// 2. 判断当前方法是不是销售
// 要代理方法名
String methodName = "saleProducer";
if (methodName.endsWith(method.getName())) {
returnValue = method.invoke(producer, money * 0.8f);
}
return returnValue;
}
});
cglibProducer.saleProducer(10000f);
}
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
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
# 3. 案例
# 1. 事务问题
- 自定义事务
public class TransactionManager {
private ConnectionUtils connectionUtils;
public void setConnectionUtils(ConnectionUtils connectionUtils) {
this.connectionUtils = connectionUtils;
}
/**
* 开启事务
*/
public void beginTransaction(){
try {
connectionUtils.getThreadConnection().setAutoCommit(false);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 提交事务
*/
public void commit(){
try {
connectionUtils.getThreadConnection().commit();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 回滚事务
*/
public void rollback(){
try {
connectionUtils.getThreadConnection().rollback();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 释放事务
*/
public void release(){
try {
// 还回连接池中,线程还回,不是关闭
connectionUtils.getThreadConnection().close();
// 把连接和线程解绑
connectionUtils.removeConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
}
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
- 使用
public Account findAccountById(Integer accountId) {
try {
// 1. 开启事务
transactionManager.beginTransaction();
// 2. 执行操作
Account account = accountDao.findAccountById(accountId);
// 3. 提交事务
transactionManager.commit();
// 4. 返回结果
return account;
} catch (Exception e) {
// 5. 回滚操作
transactionManager.rollback();
throw new RuntimeException(e);
} finally {
// 6. 释放连接
transactionManager.release();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
引发的问题: 每个方法都需要值执行上面的6步骤(代码冗余),有什么方法可以解决.?
# 2. 基于接口的动态地理方式处理
# 1. 创建代理工厂
- 代理Server增强方法
public class BeanFactory {
private AccountService accountService;
/**
* 事务工具类
*/
private TransactionManager transactionManager;
/**
* set方式注入
*
* @param accountService
*/
public void setAccountService(AccountService accountService) {
this.accountService = accountService;
}
public final void setTransactionManager(TransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
/**
* 获取Service代理对象
*
* @return
*/
public AccountService getAccountService() {
return (AccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(),
accountService.getClass().getInterfaces(),
new InvocationHandler() {
/**
* 添加事务支持
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object reValue = null;
try {
// 1. 开启事务
transactionManager.beginTransaction();
// 2. 执行操作
reValue = method.invoke(accountService, args);
// 3. 提交事务
transactionManager.commit();
// 4. 返回结果
return reValue;
} catch (Exception e) {
// 5. 回滚操作
transactionManager.rollback();
throw new RuntimeException(e);
} finally {
// 6. 释放连接
transactionManager.release();
}
}
});
}
}
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
- 配置文件
<!--配置代理Service-->
<bean id="proxyAccountService" factory-bean="beanFactory" factory-method="getAccountService"/>
<!--配置beanFactory-->
<bean id="beanFactory" class="com.chggx.factory.BeanFactory">
<!--注入Dao对象-->
<property name="accountService" ref="accountService"/>
<!--注入事务管理-->
<property name="transactionManager" ref="transactionManager"/>
</bean>
<!--配置Service-->
<bean id="accountService" class="com.chggx.service.impl.AccountServiceImpl">
<!--注入Dao对象-->
<property name="accountDao" ref="accountDao"/>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
通过代理的方式我们解决了上面出现的代码冗余问题,此时同样也出现的了一个问题.配置过于繁琐..... 我们可以利用Sprng AOP解决
上次更新: 2023/03/27, 08:56:25