动态代理

Java 提供的动态代理可以对接口进行代理,在代理的过程中主要做三件事。

  1. 拥有被代理的接口与实现类
  2. 实现 InvocationHandler 接口,重写接口内部唯一的方法 invoke。
  3. 使用 Proxy 类,通过 newProxyInstance,初始化一个代理对象。
  4. 通过代理对象,代理其他类,对该类进行增强处理。

具体可见 ; Java代理机制

第一步:

首先定义一个 IAction 接口。

1
2
3
4
package com.test.service;
public interface IAction {
void doAction();
}

提供其实现类:

1
2
3
4
5
6
7
package com.test.service;
public class Action1 implements IAction {
@Override
public void doAction() {
System.out.println("really do action");
}
}

第二步、第三步:

我们使用了 Proxy 类,调用 newProxyInstance 方法构建 IAction 接口的代理对象,而且重写了 InvocationHandler 接口中的 invoke 方法。

在重写的方法中我们判断方法名称是否与接口中的 doAction 方法保持一致,随后加上例行性逻辑(print 语句),最后通过反射调用接口 IAction 中的 doAction 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.test.service;
public class DynamicProxy {
private Object subject = null;

public DynamicProxy(Object subject) {
this.subject = subject;
}

public Object getProxy() {
//newProxyInstance()方法返回接口的代理对象
return Proxy.newProxyInstance(DynamicProxy.class
.getClassLoader(), subject.getClass().getInterfaces(),
new InvocationHandler() {
//重写invoke方法 : 在方法调用前打印文字
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("doAction")) {
System.out.println("before call real object........");
return method.invoke(subject, args);
}
return null;
}
});
}
}

第四步 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.test.controller;
public class HelloWorldBean {
//被代理的类
@Autowired
IAction action;

@RequestMapping("/testaop")
public void doTestAop(HttpServletRequest request, HttpServletResponse response) {
//代理类
DynamicProxy proxy = new DynamicProxy(action);
IAction p = (IAction)proxy.getProxy();
//方法调用
p.doAction();

}
}

问题 :

我们的目标是非侵入式编程,也就是应用程序在编程的时候,它不应该手工去创建一个代理,而是使用本来的业务接口,真正的实现类配置在外部,代理类也是配置在外部。

也就是说 :

1
2
DynamicProxy proxy = new DynamicProxy(action);
IAction p = (IAction)proxy.getProxy();

这两段代码的侵入性太强了,需要在业务逻辑程序中写上。我们要避免这段话。

引入 FactoryBean

目标

为了避免入侵性,因此将配置文件和业务代码分开,由此引入FactoryBean

即在代码中是这样的形式 :(业务类中自动注入的是一个 action,也就是上面代码里的 ProxyFactoryBean 类,这个类内部包含了真正干活儿的类 realaction。)

1
2
3
4
5
6
7
@Autowired
IAction action;

@RequestMapping("/testaop")
public void doTestAop(HttpServletRequest request, HttpServletResponse response) {
action.doAction();
}

而在配置文件中是这样的形式 :

1
2
3
4
5
<bean id="realaction" class="com.test.service.Action1" />
//如果是代理类(com.minis.aop.ProxyFactoryBean),那么就去取他的property,也就是后文所说的target
<bean id="action" class="com.minis.aop.ProxyFactoryBean" >
<property type="java.lang.Object" name="target" ref="realaction"/>
</bean>

这里就有一个初看起来非常奇怪的需求:

注册的 action bean 是 ProxyFactoryBean 类,而业务程序使用 getBean(“action”) 的时候,期待返回的又不是这个 Bean 本身,而是内部那个 target。

因为只有这样才能让业务程序实际调用 target 中的方法,外面的这个 ProxyFactoryBean 对我们来讲是一个入口,而不是目标。

这也就要求,当业务程序使用 getBean(“action”) 方法的时候,这个 ProxyFactoryBean 应该在内部进行进一步地处理,根据 target 再动态生成一个代理返回,达到侵入式编程中下面这两句话的效果。

1
2
DynamicProxy proxy = new DynamicProxy(action);
IAction p = (IAction)proxy.getProxy();

因此我们定义FactoryBean的主要目的就是,获取配置文件中内部包含的对象。

1
2
3
4
5
6
7
8
9
10
11
package com.minis.beans.factory;
public interface FactoryBean<T> {
//主要方法,从 Factory Bean 中获取内部包含的对象。
T getObject() throws Exception;

Class<?> getObjectType();

default boolean isSingleton() {
return true;
}
}

增加AbstractBeanFactory功能

接着定义 FactoryBeanRegistrySupport,提供一部分通用的方法。

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
package com.minis.beans.factory.support;
//继承DefaultSingletonBeanRegistry
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry{
protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
return factoryBean.getObjectType();
}
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName) {
Object object = doGetObjectFromFactoryBean(factory, beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
} catch (BeansException e) {
e.printStackTrace();
}
return object;
}
//最重要的是这个方法,从一个 Factory Bean 里面获取内部包含的那个 target 对象。
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) {
Object object = null;
try {
//因此要修改getObject()
object = factory.getObject();
} catch (Exception e) {
e.printStackTrace();
}
return object;
}
}

因为刚才的FactoryBeanRegistrySupport继承了 DefaultSingletonBeanRegistry

AbstractBeanFactory原来也使用了 DefaultSingletonBeanRegistry ,因此修改AbstractBeanFactory继承FactoryBeanRegistrySupport

这样就增加了AbstractBeanFactory的功能。

并且在AbstractBeanFactory中的 getBean(String beanName)方法中添加逻辑:如果 Bean 对象是 FactoryBean 类型时,则调用 getObjectForBeanInstance 方法。

如下 :

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
package com.minis.beans.factory.support;
//改为继承FactoryBeanRegistrySupport
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory,BeanDefinitionRegistry{
public Object getBean(String beanName) throws BeansException{
Object singleton = this.getSingleton(beanName);
if (singleton == null) {
//...这里是原先的内容,如果singleton == null,则创建bean的一系列步骤
}
else {
}
//这里是新增的内容,处理factorybean:如果 Bean 对象是 FactoryBean 类型时,则调用 getObjectForBeanInstance 方法。
if (singleton instanceof FactoryBean) {
return this.getObjectForBeanInstance(singleton, beanName);
}
else {
}
return singleton;
}
//getObjectForBeanInstance 方法
protected Object getObjectForBeanInstance(Object beanInstance, String beanName) {
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
//getObjectForBeanInstance 又会调用 doGetObjectFromFactoryBean 方法。
object = getObjectFromFactoryBean(factory, beanName);
return object;
}

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) {
Object object = null;
try {
object = factory.getObject();
} catch (Exception e) {
e.printStackTrace();
}
return object;
}

即在AbstractBeanFactoryFactoryBeanRegistrySupport中,都用到了 factory.getObject();,下面看一下他的实现 : ProxyFactoryBean

具体实现: ProxyFactoryBean

ProxyFactoryBean这段代码中,核心在于,ProxyFactoryBean 在 getObject() 方法中生成了一个代理 getProxy(createAopProxy()),

同样也是通过这种方式,拿到了要代理的目标对象。

这里的工作就是创建动态代理。

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
package com.minis.aop;

public class ProxyFactoryBean implements FactoryBean<Object> {
private AopProxyFactory aopProxyFactory; // AOP代理工厂
private String[] interceptorNames; // 拦截器名称数组
private String targetName; // 目标对象名称
private Object target; // 目标对象实例
private ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader(); // 代理对象的类加载器,默认使用系统类加载器
private Object singletonInstance; // 用于保存创建的代理对象的单例实例

// 构造函数,默认使用DefaultAopProxyFactory
public ProxyFactoryBean() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}

// 设置AOP代理工厂
public void setAopProxyFactory(AopProxyFactory aopProxyFactory) {
this.aopProxyFactory = aopProxyFactory;
}

// 获取AOP代理工厂
public AopProxyFactory getAopProxyFactory() {
return this.aopProxyFactory;
}

// 创建AOP代理
protected AopProxy createAopProxy() {
return getAopProxyFactory().createAopProxy(target);
}

// 设置要应用的拦截器名称
public void setInterceptorNames(String... interceptorNames) {
this.interceptorNames = interceptorNames;
}

// 获取工厂Bean的对象,即获取内部对象
@Override
public Object getObject() throws Exception {
return getSingletonInstance();
}

// 获取代理对象的单例实例
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}

// 生成代理对象
protected Object getProxy(AopProxy aopProxy) {
return aopProxy.getProxy();
}

// 获取代理对象的类型,通常返回null表示类型未知
@Override
public Class<?> getObjectType() {
return null;
}
}

基于JDK的实现

Spring提供了 AopProxy 的概念,JDK 只是AOP其中的一种实现。

1
2
3
4
package com.minis.aop;
public interface AopProxy {
Object getProxy();
}
1
2
3
4
package com.minis.aop;
public interface AopProxyFactory {
AopProxy createAopProxy(Object target);
}

实现

基于JDK的实现

这段代码是一个基于JDK动态代理实现的AOP代理类,它使用了Java的反射机制来代理目标对象的方法调用,并在 “doAction” 方法调用前添加了额外的逻辑。

这种方式允许你在不修改目标对象的情况下,通过代理对象添加横切关注点。

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
package com.minis.aop;

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

public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
Object target;

// 构造函数,接收目标对象
public JdkDynamicAopProxy(Object target) {
this.target = target;
}

// 实现AopProxy接口的方法,用于获取代理对象
@Override
public Object getProxy() {
// 使用Proxy.newProxyInstance()创建代理对象
Object obj = Proxy.newProxyInstance(
JdkDynamicAopProxy.class.getClassLoader(), // 类加载器
target.getClass().getInterfaces(), // 目标对象实现的接口
this // InvocationHandler对象,用于处理方法调用
);
return obj;
}

// 实现InvocationHandler接口的方法,处理方法调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("doAction")) {
// 在调用目标方法前添加额外的逻辑
System.out.println("-----before call real object, dynamic proxy........");
return method.invoke(target, args); // 调用目标方法
}
return null;
}
}

1
2
3
4
5
6
7
package com.minis.aop;
public class DefaultAopProxyFactory implements AopProxyFactory{
@Override
public AopProxy createAopProxy(Object target) {
return new JdkDynamicAopProxy(target);
}
}

使用

1
2
3
4
<bean id="realaction" class="com.test.service.Action1" />
<bean id="action" class="com.minis.aop.ProxyFactoryBean" >
<property type="java.lang.Object" name="target" ref="realaction"/>
</bean>
1
2
3
4
5
package com.test.service;

public interface IAction {
void doAction();
}

通过配置,我们在 HelloWorldBean 里注入的 IAction 对象就纳入了容器管理之中,因此后续测试的时候,直接使用 action.doAction(),就能实现手动初始化 JDK 代理对象的效果。

1
2
3
4
5
6
7
8
9
10
11
12
package com.test.controller;
public class HelloWorldBean {
@Autowired
IAction action;

@RequestMapping("/testaop")
public void doTestAop(HttpServletRequest request, HttpServletResponse response) {
//直接使用
action.doAction();

}
}