动态代理
Java 提供的动态代理可以对接口进行代理,在代理的过程中主要做三件事。
- 拥有被代理的接口与实现类
- 实现 InvocationHandler 接口,重写接口内部唯一的方法 invoke。
- 使用 Proxy 类,通过 newProxyInstance,初始化一个代理对象。
- 通过代理对象,代理其他类,对该类进行增强处理。
具体可见 ; 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() { return Proxy.newProxyInstance(DynamicProxy.class .getClassLoader(), subject.getClass().getInterfaces(), new InvocationHandler() { 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" /> <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> { 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;
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; } private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) { Object object = null; try { 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;
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory,BeanDefinitionRegistry{ public Object getBean(String beanName) throws BeansException{ Object singleton = this.getSingleton(beanName); if (singleton == null) { } else { } if (singleton instanceof FactoryBean) { return this.getObjectForBeanInstance(singleton, beanName); } else { } return singleton; } protected Object getObjectForBeanInstance(Object beanInstance, String beanName) { if (!(beanInstance instanceof FactoryBean)) { return beanInstance; } Object object = null; FactoryBean<?> factory = (FactoryBean<?>) beanInstance; 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; }
|
即在AbstractBeanFactory
和FactoryBeanRegistrySupport
中,都用到了 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; private String[] interceptorNames; private String targetName; private Object target; private ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader(); private Object singletonInstance;
public ProxyFactoryBean() { this.aopProxyFactory = new DefaultAopProxyFactory(); }
public void setAopProxyFactory(AopProxyFactory aopProxyFactory) { this.aopProxyFactory = aopProxyFactory; }
public AopProxyFactory getAopProxyFactory() { return this.aopProxyFactory; }
protected AopProxy createAopProxy() { return getAopProxyFactory().createAopProxy(target); }
public void setInterceptorNames(String... interceptorNames) { this.interceptorNames = interceptorNames; }
@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(); }
@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; }
@Override public Object getProxy() { Object obj = Proxy.newProxyInstance( JdkDynamicAopProxy.class.getClassLoader(), target.getClass().getInterfaces(), this ); return obj; }
@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(); } }
|