源码地址:
https://github.com/yixuaz/myspring
如看在开始前,你还不知道动态代理在JAVA里的2种实现方式,不知道BEAN POST PROCESSOR的作用。
请先看SPRING AOP 准备工作
我们开始吧。
首先同样我们要定一个目标。
AOP 的XML 应该是什么样的呢?
Step1. 在IOC 的XML 基础上加上这3行, 构建代理接口,实现2种代理
<bean id="autoProxyCreator" class="com.myspring.aop.AspectJAwareAdvisorAutoProxyCreator"></bean>
<bean id="timeInterceptor" class="com.myspring.aop.TimerInterceptor"></bean>
<bean id="aspectjAspect" class="com.myspring.aop.AspectJExpressionPointcutAdvisor">
<property name="advice" ref="timeInterceptor"></property>
<property name="expression" value="execution(* com.myspring.*.*(..))"></property>
</bean>
把该有的类创建出来。
现在XML 如下
image.png
这里的TIME INTERCEPTOR, 就是一个代理方法,也称增强方法,它的作用就是让被切到的方法,都做一个计时的增强。
为了方面我们需要引入2个AOP提供的接口。当然自己实现也是可以的。因为是接口。所以我们为了偷懒直接引入
POM.XML 加上
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
这个类写出来
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class TimerInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
long time = System.nanoTime();
System.out.println("Invocation of Method " + invocation.getMethod().getName() + " start!");
Object proceed = invocation.proceed();
System.out.println("Invocation of Method " + invocation.getMethod().getName() + " end! takes " + (System.nanoTime() - time)
+ " nanoseconds.");
return proceed;
}
}
因为AOP需要代理所以我们定一个代理接口,因为代理有2种实现,一种是JDK,一种是CGLIB。所以我们需要一个接口来屏幕底层实现。因为用户不需要关心底层SPRING用了什么实现。
public interface AopProxy {
Object getProxy();
}
下面在实现JDK的代理类前我们要思考,因为JDK的实现里,就是INVOKE里面,一个反射调用,在INVOKE方法位置做增强
image.png
我们写AOP为了通用一点,我们应该用methodInterceptor这个接口表示增强方法。然后调用这个INVOKE方法。
那这个方法又是传入一个METHOD INVOCATION,里面封装了,这个增强方法要的一切参数,不如我们先把这个实现类给写掉。
public class ReflectiveMethodInvocation implements MethodInvocation {
private Object target;
private Method method;
private Object[] args;
public ReflectiveMethodInvocation(Object target, Method method, Object[] args) {
this.target = target;
this.method = method;
this.args = args;
}
@Override
public Method getMethod() {
return method;
}
@Override
public Object[] getArguments() {
return args;
}
@Override
public Object proceed() throws Throwable {
return method.invoke(target, args);
}
@Override
public Object getThis() {
return target;
}
@Override
public AccessibleObject getStaticPart() {
return method;
}
}
解决了INVOCATION的问题,下面看还缺什么
在取得代理对象的时候,我们需要一个TAR 的CLASS 还有 INTERFACES。
image.png
所以增强方法和要代理的元数据,我们可以封装在一起,作为一个类,传入JDK动态代理PROXY里
这个类就叫AdvisedSupport
public class TargetSource {
private Class targetClass;
private Class[] interfaces;
private Object target;
public TargetSource(Object target, Class<?> targetClass,Class<?>[] interfaces) {
this.target = target;
this.targetClass = targetClass;
this.interfaces = interfaces;
}
public Class getTargetClass() {
return targetClass;
}
public Object getTarget() {
return target;
}
public Class[] getInterfaces() {
return interfaces;
}
}
public class AdvisedSupport {
MethodInterceptor methodInterceptor;
TargetSource targetSource;
public MethodInterceptor getMethodInterceptor() {
return methodInterceptor;
}
public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
this.methodInterceptor = methodInterceptor;
}
public TargetSource getTargetSource() {
return targetSource;
}
public void setTargetSource(TargetSource targetSource) {
this.targetSource = targetSource;
}
}
有了这个类之后,我们就可以把JDK PROXY写掉了。
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
AdvisedSupport advisedSupport;
public JdkDynamicAopProxy(AdvisedSupport advisedSupport) {
this.advisedSupport = advisedSupport;
}
@Override
public Object getProxy() {
return Proxy.newProxyInstance(getClass().getClassLoader(),
advisedSupport.getTargetSource().getInterfaces()}, this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInterceptor methodInterceptor = advisedSupport.getMethodInterceptor();
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advisedSupport.getTargetSource().getTarget(), method, args));
}
}
来做个简单的测试
为了测试JDK,必须要有INTERFACE,我们就为HELLOWORLD,建一个接口
public interface HelloWorldService {
void helloWorld();
}
测试
@Test
public void testInterceptor() throws Exception {
// --------- helloWorldService without AOP
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
helloWorldService.helloWorld();
// --------- helloWorldService with AOP
// 1. 设置被代理对象(Joinpoint)
AdvisedSupport advisedSupport = new AdvisedSupport();
TargetSource targetSource = new TargetSource(helloWorldService, helloWorldService.getClass(), helloWorldService.getClass().getInterfaces());
advisedSupport.setTargetSource(targetSource);
// 2. 设置拦截器(Advice)
TimerInterceptor timerInterceptor = new TimerInterceptor();
advisedSupport.setMethodInterceptor(timerInterceptor);
// 3. 创建代理(Proxy)
JdkDynamicAopProxy jdkDynamicAopProxy = new JdkDynamicAopProxy(advisedSupport);
HelloWorldService helloWorldServiceProxy = (HelloWorldService) jdkDynamicAopProxy.getProxy();
// 4. 基于AOP的调用
helloWorldServiceProxy.helloWorld();
}
测试成功:
output:Hello World!
Invocation of Method helloWorld start!
output:Hello World!
Invocation of Method helloWorld end! takes 89181 nanoseconds.
当前项目结构:
image.png
Step2 上述代码解决了怎么代理增强的问题,我们下面要解决怎么切的问题
还记得XML里* com.myspring..(..) 吗?
这个就是表示,切面的范围。
对于“在哪切”这一问题的定义,我们又叫做“Pointcut”。Spring中关于Pointcut包含两个角色:ClassFilter和MethodMatcher,分别是对类和方法做匹配。Pointcut有很多种定义方法,例如类名匹配、正则匹配等,但是应用比较广泛的应该是和AspectJ表达式的方式。
根据上述定义,我们先写一个POINTCUT 接口
public interface ClassFilter {
boolean matches(Class targetClass);
}
public interface MethodMatcher {
boolean matches(Method method, Class targetClass);
}
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
我们有了切面的接口,下面是怎么切的定义,这就是ADVISE()
在AOP里有环绕通知,前置通知,后置通知,异常通知,返回通知等。
定义一个获取通知类型的接口
import org.aopalliance.aop.Advice;//这里偷懒
public interface Advisor {
Advice getAdvice();
}
再来一个接口去获取切面和通知的的
public interface PointcutAdvisor extends Advisor{
Pointcut getPointcut();
}
接口全部定义好啦!
Step3 实现切面
首先把三个接口都实现下。
随后对于这个类来说,我们肯定会拿到一个ASPECJ表达式。所以这个表达式,要注入进来的。加一个expression 变量。
随后,我们要解析这个表达式,需要用到AOP里的PARSER了。
最后匹配方法的时候,要么全MATCH 就OK,其他都返回FALSE。
这个类的大多数代码,都是参考着org.springframework.aop.aspectj.AspectJExpressionPointcut
来写
然后做了简化如下
public class AspectJExpressionPointcut implements PointCut,ClassFilter,MethodMatcher {
private String expression;
private PointcutParser pointCutParser;
private PointcutExpression pointcutExpression;
public AspectJExpressionPointcut() {
pointCutParser = PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
}
public String getExpression() {
return expression;
}
public void setExpression(String expression) {
this.expression = expression;
}
@Override
public boolean matches(Class targetClass) {
checkReady();
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
private void checkReady() {
if(pointcutExpression == null)
pointcutExpression = pointCutParser.parsePointcutExpression(expression);
}
@Override
public boolean matches(Method method, Class targetClass) {
checkReady();
ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
if (shadowMatch.alwaysMatches()) {
return true;
}
return false;
}
@Override
public ClassFilter getClassFilter() {
return this;
}
@Override
public MethodMatcher getMethodMatcher() {
return this;
}
}
然后实现下AspectJExpressionPointcutAdvisor
这个类,主要就是对外提供ADVICE,和我们前面实现好的POINTCUT
public class AspectJExpressionPointcutAdvisor implements PointcutAdvisor {
private AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
private Advice advice;
public void setAdvice(Advice advice) {
this.advice = advice;
}
public void setExpression(String expression) {
this.pointcut.setExpression(expression);
}
@Override
public PointCut getPointCut() {
return pointcut;
}
@Override
public Advice getAdvice() {
return advice;
}
}
下面测试,
当然你可以学一下ASPECTJ EXPRESION,写出更多表达式来测试。
http://sishuok.com/forum/posts/list/281.html
Step4 实现融入Bean的创建过程,实现自己的BEAN POST PROCESSOR逻辑
现在我们有了Pointcut和Weave技术,一个AOP已经算是完成了,但是它还没有结合到Spring中去。怎么进行结合呢?Spring给了一个巧妙的答案:使用BeanPostProcessor。
BeanPostProcessor是BeanFactory提供的,在Bean初始化过程中进行扩展的接口。只要你的Bean实现了BeanPostProcessor接口,那么Spring在初始化时,会优先找到它们,并且在Bean的初始化过程中,调用这个接口,从而实现对BeanFactory核心无侵入的扩展。
那么我们的AOP是怎么实现的呢?我们知道,在AOP的xml配置中,我们会写这样一句话:
<aop:aspectj-autoproxy/>
它其实相当于:
<bean id="autoProxyCreator" class="org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator"></bean>
AspectJAwareAdvisorAutoProxyCreator就是AspectJ方式实现织入的核心。它其实是一个BeanPostProcessor。在这里它会扫描所有Pointcut,并对bean做织入。
先定义出BEAN POST PROCESSOR 这个接口
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception;
Object postProcessAfterInitialization(Object bean, String beanName) throws Exception;
}
随后根据我们上篇文章的分析,在实例化BEAN前,要把这个PROCESSOR给注册上去。
所以我们找到AbstractApplicationContext 的 refresh方法 开始加上一步
随后我们要在BEAN FACTORY 里维护所有的BEAN POST PROCESSOR
随后在BEAN 完成doCreateBean() 后 ,还需要做一个initializeBean()
更新后的BEAN FACTORY
1。实现2个新方法
第一个方法是为了提前找到并且初始化一些特定CLASS TYPE的BEAN
第二个就是维护所有的BEAN POST PROCESSOR 的BEAN
public List getBeansForType(Class<?> type) throws Exception {
List beans = new ArrayList<Object>();
for (String beanDefinitionName : beanDefinitionMap.keySet()) {
if (type.isAssignableFrom(beanDefinitionMap.get(beanDefinitionName).getBeanClass())) {
beans.add(getBean(beanDefinitionName));
}
}
return beans;
}
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
beanPostProcessors.add(beanPostProcessor);
}
随后
修改这边
@Override
public Object getBean(String beanName) throws Exception {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(beanDefinition == null)
throw new IllegalArgumentException("No bean named " + beanName + " is defined");
Object bean = beanDefinition.getBean();
if(bean == null){
bean = doCreateBean(bean,beanDefinition);
bean = initializeBean(bean, beanName);
beanDefinition.setBean(bean);
}
return bean;
}
private Object initializeBean(Object bean, String beanName) throws Exception {
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
bean = beanPostProcessor.postProcessBeforeInitialization(bean, beanName);
}
// TODO:call initialize method
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
}
return bean;
}
完整代码
public abstract class AbstractBeanFactory implements BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
private List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
@Override
public Object getBean(String beanName) throws Exception {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if(beanDefinition == null)
throw new IllegalArgumentException("No bean named " + beanName + " is defined");
Object bean = beanDefinition.getBean();
if(bean == null){
bean = doCreateBean(bean,beanDefinition);
bean = initializeBean(bean, beanName);
beanDefinition.setBean(bean);
}
return bean;
}
private Object initializeBean(Object bean, String beanName) throws Exception {
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
bean = beanPostProcessor.postProcessBeforeInitialization(bean, beanName);
}
// TODO:call initialize method
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
}
return bean;
}
protected abstract Object doCreateBean(Object bean, BeanDefinition beanDefinition) throws Exception;
public void preInstantiateSingletons() throws Exception {
for(String name : beanDefinitionMap.keySet())
getBean(name);
}
public void registerBeanDefinition(String key, BeanDefinition value) {
beanDefinitionMap.put(key, value);
}
public List getBeansForType(Class<?> type) throws Exception {
List beans = new ArrayList<Object>();
for (String beanDefinitionName : beanDefinitionMap.keySet()) {
if (type.isAssignableFrom(beanDefinitionMap.get(beanDefinitionName).getBeanClass())) {
beans.add(getBean(beanDefinitionName));
}
}
return beans;
}
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
beanPostProcessors.add(beanPostProcessor);
}
}
增加ABSTRACT APPLICATION CONTEXT 逻辑
public abstract class AbstractApplicationContext implements ApplicationContext {
protected AbstractBeanFactory beanFactory;
public AbstractApplicationContext(AbstractBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void refresh() throws Exception {
loadBeanDefinitions();
registerBeanPostProcessors(beanFactory); // new added
finishBeanFactoryInitialization();
}
private void registerBeanPostProcessors(AbstractBeanFactory beanFactory) throws Exception {
List beanPostProcessors = beanFactory.getBeansForType(BeanPostProcessor.class);
for (Object beanPostProcessor : beanPostProcessors) {
beanFactory.addBeanPostProcessor((BeanPostProcessor) beanPostProcessor);
}
}
protected void finishBeanFactoryInitialization() throws Exception {
beanFactory.preInstantiateSingletons();
}
protected abstract void loadBeanDefinitions() throws Exception;
@Override
public Object getBean(String beanName) throws Exception {
return beanFactory.getBean(beanName);
}
}
Step5 开始实现一开始新建出来一直没实现的BEAN AspectJAwareAdvisorAutoProxyCreator
在实现前,我们再理一下整个流程。
- AutoProxyCreator(实现了 BeanPostProcessor 接口)在实例化所有的 Bean 前,最先被实例化。因为registerBeanPostProcessor 在 finishInitiliazingBean 之前。
2.这个时候,他被BEAN FACTORY 通过getBeansForType 找到,并且调用了getBean(beanDefinitionName),最先实例化。
3.随后在getBEAN实例化的时候,他会先doCreateBean,这个时候,他就应该把BEAN FACTORY 给注册进去。因为之后要做postProcessAfterInitialization,来找到所有的切面我们需要用到BEAN FACTORY。
为了实现这个效果。我们搞一个接口出来。
public interface BeanFactoryAware {
public void setBeanFactory(BeanFactory beanFactory);
}
让AutoProxyCreator实现一下。
随后在doCreateBean 的 applyProPertyValues,注入BEAN FACTORY。
代码如下
private void applyProPertyValues(Object bean, BeanDefinition beanDefinition) throws Exception {
if(bean instanceof BeanFactoryAware){
((BeanFactoryAware) bean).setBeanFactory(this);
}
PropertyValues propertyValues = beanDefinition.getPropertyValues();
....
随后要实现BeanPostProcessor 的2个方法。
我们在后置处理器里实现的效果应该是,找到所有‘切面通知BEAN’(实现了这个AspectJExpressionPointcutAdvisor )或者‘’增强方法BEAN’(实现了这个MethodInterceptor),随后依次加载他们。因为他们不要被代理,所以直接RETURN。
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
if (bean instanceof AspectJExpressionPointcutAdvisor) {
return bean;
}
if (bean instanceof MethodInterceptor) {
return bean;
}
List<AspectJExpressionPointcutAdvisor> advisors = beanFactory
.getBeansForType(AspectJExpressionPointcutAdvisor.class);
...
-
其他普通 Bean 被实例化、初始化,在初始化的过程中,AutoProxyCreator 加载 BeanFactory 中所有的 PointcutAdvisor(这也保证了 PointcutAdvisor 的实例化顺序优于普通 Bean。),然后依次使用 PointcutAdvisor 内置的 ClassFilter,判断当前对象是不是要拦截的类。
-
如果是,则生成一个 TargetSource(要拦截的对象和其类型),并取出 AutoProxyCreator 的 MethodMatcher(对哪些方法进行拦截)、Advice(拦截的具体操作),再,交给 AopProxy 去生成代理对象。
//继续上面的代码
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
if (advisor.getPointCut().getClassFilter().matches(bean.getClass())) {
AdvisedSupport advisedSupport = new AdvisedSupport();
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
advisedSupport.setMethodMatcher(advisor.getPointCut().getMethodMatcher());
//这里往AdvisedSupport 多加个MethodMatcher属性
TargetSource targetSource = new TargetSource(bean, bean.getClass(),bean.getClass().getInterfaces());
advisedSupport.setTargetSource(targetSource);
return new JdkDynamicAopProxy(advisedSupport).getProxy();
}
}
return bean;
}
- AopProxy 生成一个 InvocationHandler,在它的 invoke 函数中,首先使用 MethodMatcher 判断是不是要拦截的方法,如果是则交给 Advice 来执行(Advice 由用户来编写,其中也要手动/自动调用原始对象的方法),如果不是,则直接交给 TargetSource 的原始对象来执行。
修改JDKDynamicProxy代码
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInterceptor methodInterceptor = advisedSupport.getMethodInterceptor();
if (advisedSupport.getMethodMatcher() != null
&& advisedSupport.getMethodMatcher().matches(method, advisedSupport.getTargetSource().getTarget().getClass())) {
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advisedSupport.getTargetSource().getTarget(),
method, args));
} else {
return method.invoke(advisedSupport.getTargetSource().getTarget(), args);
}
}
总结:
BeanPostProcessor :在 postProcessorAfterInitialization 方法中,使用动态代理的方式,返回一个对象的代理对象。解决了 在 IoC 容器的何处植入 AOP 的问题。
BeanFactoryAware :这个接口提供了对 BeanFactory 的感知,这样,尽管它是容器中的一个 Bean,却可以获取容器的引用,进而获取容器中所有的切点对象,决定对哪些对象的哪些方法进行代理。解决了 为哪些对象提供 AOP 的植入 的问题。
打开XML的AOP的注释
开始测试
出错了
java.lang.IllegalArgumentException: Can not set com.myspring.OutputService field com.myspring.HelloWorldServiceImpl.outputService to com.sun.proxy.$Proxy2
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
at java.lang.reflect.Field.set(Field.java:758)
at com.myspring.context.AutowireCapableBeanFactory.applyProPertyValues(AutowireCapableBeanFactory.java:40)
at com.myspring.context.AutowireCapableBeanFactory.doCreateBean(AutowireCapableBeanFactory.java:13)
at com.myspring.context.AbstractBeanFactory.getBean(AbstractBeanFactory.java:24)
at com.myspring.context.AbstractBeanFactory.preInstantiateSingletons(AbstractBeanFactory.java:49)
at com.myspring.context.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:28)
at com.myspring.context.AbstractApplicationContext.refresh(AbstractApplicationContext.java:17)
at com.myspring.context.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:19)
at com.myspring.context.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:13)
at test.HelloWorldServiceImplTest.helloWorld(HelloWorldServiceImplTest.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
猜测是JDK 动态代理没法代理非接口的OutputService
所以把这个改成接口,成功了。
image.png
Step6 我们不要接口,用CGLIB 来代理实现下吧
用一个代理工厂来智能选择代理
public interface AopProxy {
Object getProxy();
}
代理工厂,如果一个代理类有接口 就用JDK动态代理。否则就用CGLIB动态代理。
public class ProxyFactory extends AdvisedSupport implements AopProxy {
@Override
public Object getProxy() {
return createAopProxy().getProxy();
}
protected final AopProxy createAopProxy() {
if(getTargetSource().getInterfaces() == null || getTargetSource().getInterfaces().length == 0)
return new Cglib2AopProxy(this);
return new JdkDynamicAopProxy(this);
}
}
根据上一章的知识,这边不难看懂。
public class Cglib2AopProxy implements AopProxy {
AdvisedSupport advised;
public Cglib2AopProxy(AdvisedSupport advised) {
this.advised = advised;
}
public Object getProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(advised.getTargetSource().getTargetClass());
enhancer.setInterfaces(advised.getTargetSource().getInterfaces());
enhancer.setCallback(new DynamicAdvisedInterceptor(advised));
Object enhanced = enhancer.create();
return enhanced;
}
private static class DynamicAdvisedInterceptor implements MethodInterceptor {
private AdvisedSupport advised;
private org.aopalliance.intercept.MethodInterceptor delegateMethodInterceptor;
private DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
this.delegateMethodInterceptor = advised.getMethodInterceptor();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (advised.getMethodMatcher() == null
|| advised.getMethodMatcher().matches(method, advised.getTargetSource().getTargetClass())) {
return delegateMethodInterceptor.invoke(new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, args, proxy));
}
return new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, args, proxy).proceed();
}
}
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
private final MethodProxy methodProxy;
public CglibMethodInvocation(Object target, Method method, Object[] args, MethodProxy methodProxy) {
super(target, method, args);
this.methodProxy = methodProxy;
}
@Override
public Object proceed() throws Throwable {
return this.methodProxy.invoke(this.getThis(), this.getArguments());
}
}
}
最后修改AspectJAwareAdvisorAutoProxyCreator的这里
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
if (advisor.getPointCut().getClassFilter().matches(bean.getClass())) {
ProxyFactory advisedSupport = new ProxyFactory();
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
advisedSupport.setMethodMatcher(advisor.getPointCut().getMethodMatcher());
TargetSource targetSource = new TargetSource(bean, bean.getClass(),bean.getClass().getInterfaces());
advisedSupport.setTargetSource(targetSource);
return advisedSupport.getProxy();
}
}
return bean;
去掉OUTPUTSERVICE 这个接口
测试成功,OUTPUT SERVICE 由CGLIB 动态代理
HELLO WORLD SERVICE 由JDK动态代理
image.png
网友评论