Spring学习7-动态代理

动态代理

AOP的原理就是Java的动态代理机制,在Java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。

动态代理的基础 : 必须有接口.

Java中使用接口来定义统一的行为规范 : 接口

动态代理作用 : 拦截和控制 被代理对象 的所有行为.

Proxy 代理类

Class Proxy 代理类 是在运行时创建的实现指定的接口列表(称为代理接口)的类代理实例是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序对象,它实现接口InvocationHandler 。 通过其代理接口之一的代理实例上的方法调用将被分派到实例调用处理程序的invoke方法

static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 返回指定接口的代理实例,该代理实例将方法调用分派给指定的调用处理程序。

InvocationHandler 调用处理器接口

Interface InvocationHandler 每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。

案例

消费者和生产商之间加入了代理商,代理商会收取代理费。

动态代理的特点

字节码随用随创建,随用随加载。它与静态代理的区别也在于此。因为静态代理是字节码一上来就创建好,并完成加载。装饰者模式就是静态代理的一种体现。动态代理在不修改源码的基础上对方法增强。

动态代理常用的两种方式

  • 基于接口的动态代理提供者:

    JDK 官方的 Proxy 类。

    要求:被代理类最少实现一个接口。

  • 基于子类的动态代理

    提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。

    要求:被代理类不能用 final 修饰的类(最终类)。

基于接口的动态代理

  • 涉及的类: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
// IProducer.java
package com.gsynf.proxy;

/**
* 对生产厂家要求的接口
*/
public interface IProducer {
/**
* 销售
* @param money
*/
public void saleProduct(float money);

/**
* 售后
* @param money
*/
public void afterService(float money);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Producer.java
package com.gsynf.proxy;

public class Producer implements IProducer {
/**
* 销售
* @param money
*/
public void saleProduct(float money) {
System.out.println("销售产品,并拿到钱:" + money);
}
/**
* 售后
* @param 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
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// Client.java
package com.gsynf.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Client {
public static void main(String[] args) {
final Producer producer = new Producer();
IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
producer.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 {
//提供增强的代码,例如代理商拿20%
Object returnValue = null;

//1.获取方法执行的参数
Float money = (Float)args[0];
//2.判断当前方法是不是销售
if("saleProduct".equals(method.getName())) {
returnValue = method.invoke(producer, money*0.8f);
}
return returnValue;
}
});
proxyProducer.saleProduct(10000f);

}
}

基于子类的动态代理

  • 涉及的类:Enhancer

  • 提供者:第三方cglib库

  • 如何创建代理对象

    • 使用Enhancer类中的create方法
    • 创建代理对象的要求:被代理类不能是最终类
    • create方法的参数:
      • Class:字节码: 用于指定被代理对象的字节码。
      • Callback:代理增强:用于写如何代理。一般写一个接口的实现类,通常都是内部匿名类,但不必须。 此接口的实现类都是谁用谁写。 一般写的都是该接口的子接口实现类:MethodInterceptor
1
2
// Producer.java\
同上
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
// Client.java
package com.gsynf.cglib;

import com.gsynf.proxy.IProducer;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Client {

public static void main(String[] args) {
final Producer producer = new Producer();

Producer cglibProducer = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
/**
* 执行被代理对象的任何方法都会经过该方法
* @param proxy
* @param method
* @param args
* 以上三个参数和基于接口的动态代理中的invoke相同
* @param methodProxy:当前执行方法的代理对象
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//提供增强的代码,例如代理商拿20%
Object returnValue = null;

//1.获取方法执行的参数
Float money = (Float)args[0];
//2.判断当前方法是不是销售
if("saleProduct".equals(method.getName())) {
returnValue = method.invoke(producer, money*0.8f);
}
return returnValue;
}
});
cglibProducer.saleProduct(20000f);
}
}

解决案例中的问题

案例会在下一篇中做总结回顾,这里新建factory/BeanFactory.java,将业务层与事务控制完全分离。

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
63
package com.gsynf.factory;

import com.gsynf.service.IAccountService;
import com.gsynf.utils.TransactionManager;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Description: 用于创建Service的代理对象的工厂
*/
public class BeanFactory {
private IAccountService accountService;
private TransactionManager tsManager;

public final void setAccountService(IAccountService accountService) {
this.accountService = accountService;
}

public void setTsManager(TransactionManager tsManager) {
this.tsManager = tsManager;
}

/**
* 获取Service代理对象
* @return
*/
public IAccountService getAccountService() {
return (IAccountService) 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 rtValue = null;
try{
//1.开启事务
tsManager.beginTransaction();
//2.执行操作
rtValue = method.invoke(accountService,args);
//3.提交事务
tsManager.commit();
//4.返回结果
return rtValue;
}catch (Exception e) {
//5.回滚操作
tsManager.rollback();
throw new RuntimeException(e);
}finally {
//6.释放连接
tsManager.release();
}
}
});
}
}

:转载文章请注明出处,谢谢~