曹工说Spring Boot源码(19)-- Spring 带给我们的工具利器,创建代理不用愁(ProxyFactory) (5)

大家看了上面,觉得生成代理,简单,还是复杂呢?也许还不是很难。但如果是使用cglib的方式去创建代理,代码可就要多好一些了。(这个留到后面讲)

其实,spring里给我们提供了神器的,即我们要说的:ProxyFactory。其注释如下,意思是,aop代理工厂,不用通过bean factory,可以直接使用。这个类提供一个简单的获取和配置aop代理的方式。

* Factory for AOP proxies for programmatic use, rather than via a bean * factory. This class provides a simple way of obtaining and configuring * AOP proxies in code.

意思是,我们平时,实现aop,主要依靠spring的aop,即通过注解或者xml的方式,声明式地创建aop(比如配置事务时)。这里的意思是,我们可以通过代码方式来实现同样的效果,即,创建代理。

大家把这个类,理解为代理工厂即可,工厂嘛,就是给它东西,它给你返回产品,这个产品,就是代理对象。

如何利用ProxyFactory创建代理

我们看看,把它当成黑盒的话,如何利用它,来简化我们创建代理的过程:

@Test public void createJdkDynamicProxy() { ProxyFactory proxyFactory = new ProxyFactory(); // Performer performer = new Performer(); // proxyFactory.setTarget(performer); proxyFactory.addInterface(Perform.class); Perform proxy = (Perform) proxyFactory.getProxy(); log.info("proxy class:{}",proxy.getClass().getName()); proxy.sing(); log.info("proxy:{}",proxy); }

正常情况下,按照我们前面对jdk动态代理的理解,上面这样就够了。但是,上面代码会报错,说没有指定target 对象。所以,我们实际上,需要把上面那两行注释给放开,否则报如下错误。

org.springframework.aop.framework.AopConfigException: No advisors and no TargetSource specified at org.springframework.aop.framework.JdkDynamicAopProxy.<init>(JdkDynamicAopProxy.java:103) at org.springframework.aop.framework.DefaultAopProxyFactory.createAopProxy(DefaultAopProxyFactory.java:65) at org.springframework.aop.framework.ProxyCreatorSupport.createAopProxy(ProxyCreatorSupport.java:105) at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:98) at ProxyFactoryTest.createJdkDynamicProxy(ProxyFactoryTest.java:44)

上面放开那个注释代码后,默认就会去调用target的对应方法,会有如下输出:

2020-02-25 08:32:29.828 [main] INFO ProxyFactoryTest - proxy class:com.sun.proxy.$Proxy5 男孩在唱歌 2020-02-25 08:32:30.910 [main] INFO ProxyFactoryTest - proxy:foo.Performer@502775a1 如何创建代理的同时,织入切面

我们上面只是创建了代理,默认去调用了target的对应方法,假设我们要切一下,怎么办?

不慌!

@Test public void createJdkDynamicProxyWithAdvisor() { ProxyFactory proxyFactory = new ProxyFactory(); Performer performer = new Performer(); proxyFactory.setTarget(performer); proxyFactory.addInterface(Perform.class); DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(); advisor.setAdvice(new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { Object result = invocation.proceed(); System.out.println("男孩唱完要行礼"); return result; } }); proxyFactory.addAdvisor(advisor); Perform proxy = (Perform) proxyFactory.getProxy(); ProxyFactoryTest.log.info("proxy class:{}",proxy.getClass().getName()); proxy.sing(); }

这里的重点代码就是:

DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(); advisor.setAdvice(new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { Object result = invocation.proceed(); System.out.println("男孩唱完要行礼"); return result; } }); proxyFactory.addAdvisor(advisor);

这上面的几行代码,主要是创建了一个advisor,一个advisor 几乎等于切点+通知。

advisor的setAdvice呢,主要接受一个Advice类型的参数。而MethodInterceptor就是它的子接口。

曹工说Spring Boot源码(19)-- Spring 带给我们的工具利器,创建代理不用愁(ProxyFactory)

当然了,其实advice的实现很多,包括spring里都有很多内部实现。我这里找了一个,对方法执行耗时,进行监测的。

我把上面的代码改动了一行:

advisor.setAdvice(new PerformanceMonitorInterceptor());

这个类,的继承关系如下:

曹工说Spring Boot源码(19)-- Spring 带给我们的工具利器,创建代理不用愁(ProxyFactory)

主要功能就是记录耗时,此时,输出如下:

2020-02-25 08:40:06.825 [main] INFO ProxyFactoryTest - proxy class:com.sun.proxy.$Proxy5
男孩在唱歌
2020-02-25 08:40:07.868 [main] TRACE o.s.aop.interceptor.PerformanceMonitorInterceptor - StopWatch 'foo.Perform.sing': running time (millis) = 1006

总结

今天大概讲了jdk动态代理的原理,和ProxyFactory的使用。下一讲,继续aop之旅,主要讲解ProxyFactory的原理。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywjjf.html