Java AOP (2) runtime weaving 【Java 切面编程 (2) 运行时织入】
接上一篇 Java AOP (1) compile time weaving 【Java 切面编程 (1) 编译期织入】
Dynamic proxy 动态代理
Befor talking about runtime weaving, let's take a look at Java dynamic proxy.
在说运行时织入之间,我们先看看java动态代理
public class DynamicProxyTest { public interface Vehicle { void whistle(); } public static class Boat implements Vehicle { @Override public void whistle() { System.out.println( "Boat whistle!" ); } } public static class VehicleHandler implements InvocationHandler { private Object proxied; public VehicleHandler(Object proxied ) { this.proxied = proxied; } public Object invoke(Object proxy, Method method, Object[] args ) throws Throwable { checkVehicle(); return method.invoke( proxied, args); } private void checkVehicle() { System.out.println("Check vehicle status ..."); } } public static void main(String[] args) throws Exception { Boat boat = new Boat(); boat.whistle(); System.out.println("--------------------------"); Vehicle proxyBoat = (Vehicle) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), new Class[]{Vehicle.class}, new VehicleHandler(boat)); proxyBoat.whistle(); } }
Output:
Boat whistle! -------------------------- Check vehicle status ... Boat whistle!
Note the marked codes, we add an InvocationHandler class and then create a new proxy instance based on that. After the proxy object is generated, every method in vehicle will be invoked with an addition checkVehicle() call.
注意标红的代码,我们增加了一个请求处理类,然后基于它创建了一个代理实例。代理对象被创建之后,针对它的每一个方法调用都会伴随着一次额外的checkVehicle函数调用。
What's the magic behind dynamic proxy? Let's trace the JDK source code.
动态代理的底层魔法是什么呢? 来看看JDK源码一探究竟。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { ....... /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ ........ return cons.newInstance(new Object[]{h}); }
The getProxyClass0 method will generate a proxy class using ProxyClassFactory
newProxyInstance 会首先用getProxyClass0方法,然后继续调用 ProxyClassFactory 工厂类来生成一个代理类,继而产生代理实例。
/** * A factory function that generates, defines and returns the proxy class given * the ClassLoader and array of interfaces. */ private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { .......... }
After the proxy class is finally generated, every interface method will looks like
当实例类生成之后,每一个方法的实现大致如下
public final int customizedMethod() { try { return ((Integer)super.h.invoke(this, m0, null)).intValue(); } catch(Exception e) { ....... } }
The marked part tells why the implementation of invocation handler becomes so useful, it becomes the entrance of every interface method.
标红部分会调用之前 InvocationHandler 方法中的自定义的 invoke 方法,它成为了每一个接口方法的入口函数。
Spring AOP
Official document https://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
11.1.3 AOP Proxies
Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied.
Spring AOP can also use CGLIB proxies. This is necessary to proxy classes rather than interfaces. CGLIB is used by default if a business object does not implement an interface. As it is good practice to program to interfaces rather than classes; business classes normally will implement one or more business interfaces. It is possible toforce the use of CGLIB, in those (hopefully rare) cases where you need to advise a method that is not declared on an interface, or where you need to pass a proxied object to a method as a concrete type.
It is important to grasp the fact that Spring AOP is proxy-based. See Section 11.6.1, “Understanding AOP proxies” for a thorough examination of exactly what this implementation detail actually means.
JDK proxy --> proxy interface, CFLIB proxy --> proxy any class
根据Spring的官方文档,Spring AOP有两种实现。 对于接口,默认使用JDK动态代理,而对于无接口实现的普通类,默认使用CGLIB进行代理。
Next, a demo will show how to use Spring AOP based on maven.
接下来将会演示如何使用Spring AOP
1) Add dependency
增加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
2) Create a simple spring boot app
创建一个简单的spring boot应用
@SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(AppConfig.class, args); } } @Configuration @ComponentScan public class AppConfig extends WebMvcConfigurerAdapter { @Autowired HandlerInterceptor apiInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(apiInterceptor); } } @RestController public class SimpleController { @RequestMapping("/greeting") public String greeting(@RequestParam(value="name", defaultValue="World") String name) { ExpressionParser parser = new SpelExpressionParser(); Expression exp = parser.parseExpression("'root.methodName'"); String message = exp.getValue(String.class); return message; } @RequestMapping("/hello") public ResponseEntity hello(@RequestParam(value="name", defaultValue = "SYSTEM") String name) { return ResponseEntity.ok().body("Hello from " + name); } }
3) Define an aspect class
定义一个切面类
@Aspect @Component public class ExecutionLogger { private Logger logger; public ExecutionLogger() { logger = LoggerFactory.getLogger(getClass()); logger.info("Execution time logger created."); } @Pointcut("execution(* spring.SimpleController.*(*))") public void methodPointcut() { } @Around("methodPointcut()") public Object proceed(ProceedingJoinPoint pjp) throws Throwable { String name = pjp.getSignature().getName(); logger.info("This is aop join point before [{}]", name); try { return pjp.proceed(); } finally { } } }
@Aspect, @Pointcut and @Around annotations makes it very convinient to use Spring AOP.
We can add point cut at any method around which cutomized process like log, time evaluation, etc can be added.
Aspect, Pointcut, Around注解使得使用Spring AOP变得很简单
我们可以在想要切入的方法上加入切点(通过Pointcut注解完成),然后在通过Around注解实现具体的切面逻辑。
4) Open browser, visit greeting controller
打开浏览器,访问刚刚定义的greeting
Below is console output
下面是控制台输出,可以看到每次greeting页面被打开时会有一条调用记录
2017-05-09 14:04:38.814 INFO 7580 --- [ XNIO-2 task-1] spring.ExecutionLogger : This is aop join point before [greeting]
Java AOP (2) runtime weaving 【Java 切面编程 (2) 运行时织入】的更多相关文章
- Java AOP (1) compile time weaving 【Java 切面编程 (1) 编译期织入】
According to wikipedia aspect-oriented programming (AOP) is a programming paradigm that aims to inc ...
- Spring AOP 之编译期织入、装载期织入、运行时织入(转)
https://blog.csdn.net/wenbingoon/article/details/22888619 一 前言 AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP ...
- Java AOP nested exception is java.lang.NoClassDefFoundError: org/aopalliance/aop/Advice || Error creating bean with name 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0' 两个异常解决办法
贴出applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans ...
- 深入理解JAVA虚拟机之JVM性能篇---基础知识点(运行时数据区域)
一. 运行数据区域划分 各个数据区域功能如下: 1. 程序计数器: 较小的一块内存空间,可以看做是当前线程所执行的字节码的行号指示器,每条线程都有一个独立的程序计数器,各条线程之间计数器互不影响,独立 ...
- 深入理解Java虚拟机 -- 读书笔记(1):JVM运行时数据区域
深入理解Java虚拟机 -- 读书笔记:JVM运行时数据区域 本文转载:http://blog.csdn.net/jubincn/article/details/8607790 本系列为<深入理 ...
- java中exception和error有什么区别,运行时异常和一般异常有什么区别
1.exception和error都是继承了throwable类,在java中只有throwable类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型 2.ex ...
- Java虚拟机所管理的内存,包含的运行时数据区域?
运行时数据区域 线程私有(随用户线程的启动和结束而建立和销毁)或所有线程共享(随虚拟机进程的启动而存在) 抛出的异常 备注 程序计数器(Program Counter Register) 线程私有 唯 ...
- java动态编程库,利用动态编程打印运行时调用全景(函数调用关系链)
如果是一般java程序,不追求性能极致,想使用方便,推荐使用 Javassist 库. 如果是android程序,或者一般java程序欲追求性能极限,推荐使用 asm for java 及 asmde ...
- 04—AOP 实现项目中的切面编程
随机推荐
- QQGame防专线中断系统介绍
先说说背景 QQGame是一个全区全服的休闲类游戏平台和社区,主逻辑服务器部署在四大IDC,核心DB全部在深圳.对跨IDC的专线依赖度很高. 网平提供专线故障后切VPN的备份机制,当VPN也中断时QQ ...
- Android 5.0及以上版本使用webview不能存储第三方Cookies解决方案
Android 5.0以上的手机使用原生WebView浏览网页,在进行登录的时候会提示验证码错误,通过查找5.0以上系统的api文档,发现5.0以上版本的webview做了较大的改动,如:同步cook ...
- 【JavaWeb】Session(转)
Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自 ...
- 2017-3-28 javaScript DOM 操作
一.DOM的基本概念:DOM是文档对象模型,这种模型为树模型:文档是指标签文档:对象是指文档中每个元素:模型是指抽象化得东西. 二.Windows 对象操作:1.属性和方法:属性(值或者子对象):o ...
- 如何将多条update语句合并为一条
需求: 如何将多条update语句合并为一条update语句:如,update table1 set col='2012' where id='2014001' update table1 ...
- 深度学习实践系列(2)- 搭建notMNIST的深度神经网络
如果你希望系统性的了解神经网络,请参考零基础入门深度学习系列,下面我会粗略的介绍一下本文中实现神经网络需要了解的知识. 什么是深度神经网络? 神经网络包含三层:输入层(X).隐藏层和输出层:f(x) ...
- 【转】HTML5 API --- 页面可见性改变(visibilitychange)事件
[摘要:[本文属本创,若有转载,请说明出处http://blog.csdn.net/yl02520/article/] visibilitychange事情是扫瞄器新增加的一个事情,当扫瞄器的某个标签 ...
- BloomFilter算法
Bloom filter 是由 Howard Bloom 在 1970 年提出的二进制向量数据结构,它具有很好的空间和时间效率,被用来检测一个元素是不是集合中的一个成员.如果检测结果为是,该元素不一定 ...
- Codeforces Round #384 (Div. 2).C
C. Vladik and fractions time limit per test 1 second memory limit per test 256 megabytes input stand ...
- 看Lucene源码必须知道的基本概念
终于有时间总结点Lucene,虽然是大周末的,已经感觉是对自己的奖励,毕竟只是喜欢,现在的工作中用不到的.自己看源码比较快,看英文原著的技术书也很快.都和语言有很大关系.虽然咱的技术不敢说是部门第一的 ...