http://www.iteye.com/topic/481813
DDD 现在越来越流行了, 不管正确与否, new User().save() 这样的写法相对千篇一律的 service dao transaction script 总是显得更酷也更具吸引力, save 方法一般来说是这个样子
- public void save() {
- userRepository.save(this);
- }
看起来很自然, 但如何取得 userRepositry 却一直是个难题, 现在 jdk5 新增的 Instrumentation 机制使得这个问题有了一个标准解决方案 : 通过 instrumentation 的动态字节码增强在装载期向 domain object 中注入依赖, 也就是本文的主题 LoadTimeWeaver, aspectj 很早就开始支持这个功能, 今天我们主要探讨一下 spring 基于 aspectj 的 LoadTimeWeaver 支持和一些常见问题.
spring load time weaver 主要通过以下步骤完成 :
1. 在启动程序的 jvm argument 中增加 spring-agent.jar 以获得 jvm 导出的 instrumentation
2. aspectj 拦截 domain object 的创建
3. 在 AnnotationBeanConfigurerAspect 中完成对 domain object 的注入
下面详细说明
1. Add spring-agent.jar to jvm argument
如果是命令行启动, 使用 java -javaagent:#{your path}/spring-agent.jar MyProgram 命令启动程序, 如果是 ide, 在 jvm argument 中增加 -javaagent:#{your path}/spring-agent.jar 即可.
增加这个参数的目的就是获取 jvm 导出的 instrumentation 引用以便后续操作的进行, 打开 spring-agent.jar 的 META-INF/MENIFEST.MF 会发现其中一句 : Premain-Class: org.springframework.instrument.InstrumentationSavingAgent, 没错, 根据 instrumentation 规范, Premain-Class 就是用于处理 instrumentation 的入口, 事实上 spring-agent.jar 里也只有这一个 class, 打开代码会发现非常简单 :
- public class InstrumentationSavingAgent {
- private static volatile Instrumentation instrumentation;
- /**
- * Save the {@link Instrumentation} interface exposed by the JVM.
- */
- public static void premain(String agentArgs, Instrumentation inst) {
- instrumentation = inst;
- }
- }
在 premain 方法里将 instrumentation 保存到 static 引用中以便后续访问.
2. 配置 spring 支持 load time weaver
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context.xsd">
- <context:annotation-config />
- <context:load-time-weaver aspectj-weaving="on" />
- <bean class="example.ltw.DefaultUserRepository" />
- </beans>
通过 <context:load-time-weaver aspectj-weaving="on" /> 使 spring 开启 loadtimeweaver, 注意 aspectj-weaving 有三个选项 : on, off, auto-detect,
建议设置为 on 以强制使用 aspectj, 如果设置为 auto-detect, spring 将会在 classpath 中查找 aspejct 需要的 META-INF/aop.xml, 如果找到则开启 aspectj weaving, 这个逻辑在 LoadTimeWeaverBeanDefinitionParser#isAspectJWeavingEnabled 方法中
- protected boolean isAspectJWeavingEnabled(String value, ParserContext parserContext) {
- if ("on".equals(value)) {
- return true;
- }
- else if ("off".equals(value)) {
- return false;
- }
- else {
- // Determine default...
- ClassLoader cl = parserContext.getReaderContext().getResourceLoader().getClassLoader();
- return (cl.getResource(ASPECTJ_AOP_XML_RESOURCE) != null);
- }
- }
3. Code of User
- @Configurable(autowire = Autowire.BY_TYPE)
- public class User {
- @Resource
- // 或使用 @Autowired
- private UserRepository userRepository;
- public void save() {
- userRepository.save(this);
- }
- }
4. 将 spring-agent.jar, spring-aspects.jar, aspectj-weaver.jar, aspectj-rt.jar 加入到 classpath 中, 运行期主要发生以下调用 :
- LoadTimeWeaverBeanDefinitionParser (spring.jar) // 解析配置
- -> AspectJWeavingEnabler (spring.jar) // 开启 aspectj weaving
- -> InstrumentationSavingAgent (spring-agent.jar) // 获取 instrumentation
- -> InstrumentationLoadTimeWeaver#addTransformer (spring.jar) // 增加 aspectj class transformer 到 instrumentation
- -> ClassPreProcessorAgentAdapter#transform (aspectj-weaver.jar) // aspectj 拦截 domain object 装载
- -> AnnotationBeanConfigurerAspect#configureBean (spring-aspects.jar) // spring 注入依赖到标注了 @Configurable 的对象中
至此完成整个 load time weave 过程.
注意前文中的 <context:annotation-config /> 并不是必须的, 如果不配置, userRepository 就不能用 annotation(@Resource 或 @Autowired) 注入而必须使用 set 方法.
5. What's in spring-aspects.jar
spring-aspects.jat 是一个独立的 jar, 它并不被包含于常用的 spring.jar 中, 其中的 META-INF/aop.xml 定义了 aspectj 需要的配置, AnnotationBeanConfigurerAspect 负责注入依赖到标注了 @Configurable domain object 中 :
- public pointcut inConfigurableBean() : @this(Configurable);
- public pointcut preConstructionConfiguration() : preConstructionConfigurationSupport(*);
- declare parents: @Configurable * implements ConfigurableObject;
- public void configureBean(Object bean) {
- // 这里执行了 inject
- beanConfigurerSupport.configureBean(bean);
- }
附件是文中的示例项目, 运行 LoadTimeWeaverTest 即可.
PS : Spring 也可以使用一些特定应用服务器的 ClassLoader 实现 LoadTimeWeaver, 如有兴趣请参考相应文档, 本文不再赘述.
相关推荐
NULL 博文链接:https://liuwenbo200285.iteye.com/blog/986608
For environments where class instrumentation is required but are not supported by the existing LoadTimeWeaver implementations, a JDK agent can be the only solution. For such cases, Spring provides ...
Getting started with Spring Framework (4th Edition) is a hands-on guide to begin developing applications using Spring Framework 5. The examples (consisting of 88 sample projects) that accompany this ...
Spring源代码解析(一):Spring中的事务处理 Spring源代码解析(二):ioc容器在Web容器中的启动 Spring源代码分析(三):Spring JDBC Spring源代码解析(四):Spring MVC Spring源代码解析(五):Spring AOP获取Proxy ...
Spring boot 是 Spring 的一套快速配置脚手架,可以基于spring boot 快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的云应用开发工具;Spring boot专注于快速、方便集成的单个个体,Spring Cloud是关注...
Spring3.2 Spring4.3 Spring5.0三个版本的jar包,都是官方下载,亲测可用,放心下载。
spring boot , spring cloud alibaba, spring cloub 版本选型
Classes contained in spring-mock.jar: org.springframework.mock.jndi.ExpectedLookupTemplate.class org.springframework.mock.jndi.SimpleNamingContext.class org.springframework.mock.jndi....
spring3.1官方所有的jar包 org.springframework.aop-3.1.RELEASE.jar org.springframework.asm-3.1.RELEASE.jar org.springframework.aspects-3.1.RELEASE.jar org.springframework.beans-3.1.RELEASE.jar org....
spring中AOP中标签加载通知,spring中AOP中标签加载通知spring中AOP中标签加载通知spring中AOP中标签加载通知,spring中AOP中标签加载通知
将spring2的开发包spring.jar替换为附件中压缩文件的所有jar包,既可以将spring2.0的应用升级到spring3.0.5
spring4.x中的jar包下载,spring4.0.6下载,spring最新稳定版jar包下载 http://maven.springframework.org/release/org/springframework/spring/ 这个链接中有各种稳定版的jar包下载 目前官网上大部分都要maven下载
spring-aop-1.1.1.jar spring-aop-1.2.6.jar spring-aop-1.2.9.jar spring-aop-2.0.2.jar spring-aop-2.0.6.jar spring-aop-2.0.7.jar spring-aop-2.0.8.jar spring-aop-2.0.jar spring-aop-2.5.1.jar spring-aop-...
很好的一个spring教程很好的一个spring教程很好的一个spring教程很好的一个spring教程很好的一个spring教程很好的一个spring教程很好的一个spring教程很好的一个spring教程
spring 3.2.4 Realease 的所有jar包: spring-context-3.2.4.RELEASE.jar spring-core-3.2.4.RELEASE.jar spring-beans-3.2.4.RELEASE.jar spring-test-3.2.4.RELEASE.jar spring-web-3.2.4.RELEASE.jar spring-aop-...
Spring技术内幕:深入解析Spring架构与设计原理(第2部分) 《Spring技术内幕:深入解析Spring架构与设计原理》是Spring领域的问鼎之作,由业界拥有10余年开发经验的资深Java专家亲自执笔!Java开发者社区和Spring...
spring_dubbo spring_dubbospring_dubbospring_dubbospring_dubbospring_dubbospring_dubbospring_dubbospring_dubbospring_dubbospring_dubbospring_dubbospring_dubbospring_dubbospring_dubbospring_dubbospring_...
通过一个使用Spring、Spring Boot和Spring Cloud的小例子来说明如何构建微服务系统。 具体请看附件文件中的:readme.txt 和 [译]Spring构建微服务.png 访问地址:http://localhost:1111/ 运行顺序:...
Spring Boot整合Spring Batch的一个小例子,在网上发现这方面的资源比较少,特此将其上传供大家学习。