- 浏览: 240123 次
- 性别:
- 来自: 上海
最新评论
-
weigeshikebi:
不得不赞一个
解惑 spring 嵌套事务 -
siemens800:
Mac OS X 10.7.2 的光盘还有挖,帅锅帮刻个盘发来 ...
MacBook 升级内存记 -
cry615:
帖子很不错,java里任何一个东西都是一门学问,很有很强的逻辑 ...
理解 Java 的 GC 与 幽灵引用 -
sharkka:
sogo1986 写道楼主举的例 ...
解惑 spring 嵌套事务 -
sogo1986:
楼主举的例子并没用体 ...
解惑 spring 嵌套事务
DDD 现在越来越流行了, 不管正确与否, new User().save() 这样的写法相对千篇一律的 service dao transaction script 总是显得更酷也更具吸引力, save 方法一般来说是这个样子
看起来很自然, 但如何取得 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, 打开代码会发现非常简单 :
在 premain 方法里将 instrumentation 保存到 static 引用中以便后续访问.
2. 配置 spring 支持 load time weaver
通过 <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 方法中
3. Code of User
4. 将 spring-agent.jar, spring-aspects.jar, aspectj-weaver.jar, aspectj-rt.jar 加入到 classpath 中, 运行期主要发生以下调用 :
至此完成整个 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 中 :
附件是文中的示例项目, 运行 LoadTimeWeaverTest 即可.
PS : Spring 也可以使用一些特定应用服务器的 ClassLoader 实现 LoadTimeWeaver, 如有兴趣请参考相应文档, 本文不再赘述.
王政 于 2009, 10, 5
手动注入可以增加 setter method, 示例代码是为了简洁以及演示 annotation injection 的用法
将不自然属于任何一个 Entity 或 Value Object 的逻辑封装到无状态的 Service 中, eg
保持一个事务跟跨越多个实体没什么关系吧, 只要把事务控制放在最外层就好了, 比如这样
例子中的 user 没有跟其他实体关联是想让代码更简洁, 毕竟只是为了演示 loadtimeweaver
至于你说的通过构造函数或方法注入当然是可以的, 但是 loadtimeweaver 就是为了省去这个步骤才出现的, 否则你代码里只要有构造实体的地方就会有大驼大驼的 inject 方法调用, 那就不是 dependency injection 而是 manual injection 了, 像这个样子
如果要调用 getAge 方法就必须需要手动注入 TimeService, 然后你的 repository 就变成了这样
对 inject 的调用在每一个构造实体的地方都要发生, 不但乏味而且容易遗漏, loadtimeweaver 要解决的正是这个问题 : 一次配置 到处使用
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, 如有兴趣请参考相应文档, 本文不再赘述.
王政 于 2009, 10, 5
- springltw.zip (8 KB)
- 下载次数: 200
评论
8 楼
Feiing
2009-10-09
mikab 写道
看起来非常酷,确实是一种解决domain对象的依赖注入的思路。
但是我看在你的代码里所有的Repositry都是private的,会不会导致你的domain对象脱离了你用spring构建起来的环境就基本不能用了?我觉得这个违背了对pojo的定义。
但是我看在你的代码里所有的Repositry都是private的,会不会导致你的domain对象脱离了你用spring构建起来的环境就基本不能用了?我觉得这个违背了对pojo的定义。
手动注入可以增加 setter method, 示例代码是为了简洁以及演示 annotation injection 的用法
7 楼
mikab
2009-10-09
看起来非常酷,确实是一种解决domain对象的依赖注入的思路。
但是我看在你的代码里所有的Repositry都是private的,会不会导致你的domain对象脱离了你用spring构建起来的环境就基本不能用了?我觉得这个违背了对pojo的定义。
但是我看在你的代码里所有的Repositry都是private的,会不会导致你的domain对象脱离了你用spring构建起来的环境就基本不能用了?我觉得这个违背了对pojo的定义。
6 楼
Feiing
2009-10-08
by5739 写道
需要在一个事物当中更新2个实体, 不知道该如何写代码?
例如出库动作,需要更新库存的同时产生一张最终出库单,这2个对象并没有直接的联系
例如出库动作,需要更新库存的同时产生一张最终出库单,这2个对象并没有直接的联系
将不自然属于任何一个 Entity 或 Value Object 的逻辑封装到无状态的 Service 中, eg
public class WarehourseService { @Transactional public void withdrawal(Cargo cargo, double amount) { cargo.updateInventory(amount); new WarehouseOrder(cargo).save(); } }
5 楼
by5739
2009-10-08
需要在一个事物当中更新2个实体, 不知道该如何写代码?
例如出库动作,需要更新库存的同时产生一张最终出库单,这2个对象并没有直接的联系
例如出库动作,需要更新库存的同时产生一张最终出库单,这2个对象并没有直接的联系
4 楼
Feiing
2009-10-07
didiluck 写道
我经常碰到的XXXRepository都是跨越多个实体的,要保持一个事务,像楼主这样注入到实体中,适用面不广吧,我觉得把Repository通过实体的构造函数或者是函数参数的方法引入到实体中也挺不错的。
保持一个事务跟跨越多个实体没什么关系吧, 只要把事务控制放在最外层就好了, 比如这样
new User().addRole(role).save();
例子中的 user 没有跟其他实体关联是想让代码更简洁, 毕竟只是为了演示 loadtimeweaver
至于你说的通过构造函数或方法注入当然是可以的, 但是 loadtimeweaver 就是为了省去这个步骤才出现的, 否则你代码里只要有构造实体的地方就会有大驼大驼的 inject 方法调用, 那就不是 dependency injection 而是 manual injection 了, 像这个样子
public class User { private Date birth; @Resource private UserRepositry userRepositry; @Resource private TImeService timeService; public int getAge() { return timeService.currentTime().substract(birth).years(); } }
如果要调用 getAge 方法就必须需要手动注入 TimeService, 然后你的 repository 就变成了这样
public class UserRepository { public User load(id) { User user = hibernateTemplate.load(id); return inject(user); } public List<User> find() { return hibernateTemplate.find().transform( new Tranformer() { public User tranform(User each) { return inject(each); } } ); } private User inject(User user) { user.setUserRepository(userRepository); user.setTimeService(timeService); return user; } }
对 inject 的调用在每一个构造实体的地方都要发生, 不但乏味而且容易遗漏, loadtimeweaver 要解决的正是这个问题 : 一次配置 到处使用
3 楼
didiluck
2009-10-07
我经常碰到的XXXRepository都是跨越多个实体的,要保持一个事务,像楼主这样注入到实体中,适用面不广吧,我觉得把Repository通过实体的构造函数或者是函数参数的方法引入到实体中也挺不错的。
2 楼
Feiing
2009-10-06
加入 xercesImpl 正常运行的话可能是 jdk 版本问题, 你是 1.5 or 1.6 ? 1.6 已经包含了 xml parser 应该不需要加
1 楼
ftj20003
2009-10-05
试验的过程中,报错:
Caused by: java.lang.RuntimeException: Installation Problem??? Couldn't load messages: Can't find bundle for base name org.apache.xerces.impl.xpath.regex.message, locale zh_CN
后来跟踪并且上网查了相关的问题,加入xercesImpl.jar即可正常运行了,但是不知道具体的原因,请问lz碰到过吗?能不能解释一下产生这个错误的原因。。。
Caused by: java.lang.RuntimeException: Installation Problem??? Couldn't load messages: Can't find bundle for base name org.apache.xerces.impl.xpath.regex.message, locale zh_CN
后来跟踪并且上网查了相关的问题,加入xercesImpl.jar即可正常运行了,但是不知道具体的原因,请问lz碰到过吗?能不能解释一下产生这个错误的原因。。。
发表评论
-
Bookmarks
2010-07-07 16:42 1526Architecture J2EE cluster htt ... -
XML validation error on request: cvc-complex-type
2010-04-15 21:45 1377see http://72.5.124.102/threa ... -
理解 Java 的 GC 与 幽灵引用
2009-06-04 03:02 3288理解 Java 的 GC 与 幽灵引用 J ... -
基于 Apache Mina 的 RPC 实现 (长连接 webservice)
2008-11-27 23:26 4390写了一个基于 Apache Mina 和 SpringRemo ... -
Atomikos JTA for Hibernate3
2007-11-22 14:52 3365http://wiki.atomikos.org/bin/vi ... -
Spring AOP 概览与细节
2007-08-05 03:21 6034@王政 @2007-08-04 @转载请注明 ... -
解惑 spring 嵌套事务
2006-11-25 01:03 36206解惑 spring 嵌套事务 /** * @au ... -
使用 FactoryBean 让你的 spring 配置动起来
2006-11-01 17:43 10493看到不少朋友讨论 spring 配置时认为 spring 配置 ... -
一个可能的列级权限控制方案讨论
2006-05-25 18:45 18014最近的项目需要做到列级权限控制, 大意如下 publi ... -
Spring 事务简化配置
2006-03-21 00:33 36798在 spring 中, 事务管理一般是通过声明一个 txPr ... -
再论 Acegi 权限存储策略
2006-02-18 00:17 12865本文原出处 http://starcraft.blogdriv ... -
以前写的一篇介绍 Acegi 的文档
2006-01-05 09:51 13298半年前写的, 版本是 0.8.3, 主要是翻译了一些 ref ... -
Acegi 资源配置动态扩展实现
2005-12-13 16:21 19199本文原出处 : http://starcr ...
相关推荐
本文将深入探讨"Spring 3.0 + Hibernate 3.5整合那些事儿",结合给出的标签"源码"和"工具",我们将讨论如何将这两个强大的框架结合在一起,以及在整合过程中可能遇到的问题和解决方案。 首先,Spring是一个全面的...
在这个压缩包中,包含的文件名为“java那些事儿.chm”。 Java,作为世界上最流行的编程语言之一,拥有广泛的应用领域,从企业级应用到移动开发,无处不在。这个CHM文档很可能是对Java基础知识、进阶概念、实战技巧...
在Java开发领域,Spring Boot和Spring Batch的整合是构建高效批处理系统的一种常见方式。Spring Boot以其简洁的配置和快速的启动能力深受开发者喜爱,而Spring Batch作为Spring框架的一部分,专注于批量处理任务,...
- 对于需要稳定性和长期支持的老项目,建议选择2021.x或2.2.x分支,尤其是那些已经使用Spring Boot 2.4及以下版本的项目。 - 在选择版本时,务必参考官方文档中的依赖关系图表,确保所选版本能够顺利地与其他组件...
Spring框架是Java应用程序开发中的一个核心组件,它提供了一个丰富的IOC(Inversion of Control,控制反转)和AOP(Aspect-Oriented Programming,面向切面编程)功能,使得开发者能够更方便地管理对象和实现模块化...
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 ...
Spring Integration + Spring WS 整合 在 Java 领域中,Spring Integration 和 Spring WS 是两个常用的框架,它们分别负责集成系统和 Web 服务。今天,我们将探讨如何将这两个框架整合在一起,实现一个完整的 Web ...
这个模块主要实现了`org.springframework.instrument.classloading`包下的接口,例如`LoadTimeWeaver`,它的作用是在类加载时进行代码修改或增强,这在AOP(面向切面编程)和代理类生成等场景下尤其有用。...
Spring Batch是一个轻量级的,完全面向Spring的批处理框架,可以应用于企业级大量的数据处理系统。Spring Batch以POJO和大家熟知的Spring框架为基础,使开发者更容易的访问和利用企业级服务。Spring Batch可以提供...
在构建分布式系统时,Spring Cloud Gateway 作为微服务架构中的边缘服务或 API 网关,扮演着至关重要的角色。它负责路由请求到相应的微服务,并可以提供过滤器功能,如限流、熔断等。而Spring Security 则是 Java ...
在Spring Instrument源码中,我们可以看到`org.springframework.instrument.classloading.LoadTimeWeaver`接口扮演着关键角色。它定义了如何在类加载时进行织入(weaving),即在类加载到内存之前或之后插入额外的...
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 3.0.5的所有jar文件: org.springframework.aop-3.0.5.RELEASE.jar org.springframework.asm-3.0.5.RELEASE.jar org.springframework.aspects-3.0.5.RELEASE.jar org.springframework.beans-3.0.5.RELEASE...
spring揭秘,了解spring内在运行逻辑
Spring Framework 是Java开发中的核心框架,它以其强大的功能和易用性成为了许多...对于那些寻找高质量Spring中文资料的人来说,这是一个值得信赖的在线资源,无需注册或关注,直接在https://springdoc.cn/ 就能访问。
这个版本在Spring 5.0发布之前提供了一个稳定可靠的平台,尤其对于那些尚未准备好升级到Java 8或Spring 5的项目来说,它是理想的选择。 Spring框架的核心特性包括依赖注入(Dependency Injection,DI),面向切面...
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 实战第六版" Spring Framework 是一个广泛使用的 Java 应用程序框架,它提供了一个通用的编程模型和配置机制,帮助开发者快速构建企业级应用程序。下面是对 Spring Framework 的详细知识点总结: 1. 什么...
在IT行业中,Spring框架是Java应用开发中的一个关键组件,它提供了一整套服务来简化企业级应用的构建。RabbitMQ则是一个流行的开源消息队列系统,它基于AMQP(Advanced Message Queuing Protocol)协议,用于高效地...