`

[转]spring容器外注入

阅读更多

转自:http://www.iteye.com/topic/481813 

DDD 现在越来越流行了, 不管正确与否, new User().save() 这样的写法相对千篇一律的 service dao transaction script 总是显得更酷也更具吸引力, save 方法一般来说是这个样子 

Java代码  收藏代码
  1. public void save() {  
  2.     userRepository.save(this);  
  3. }  



看起来很自然, 但如何取得 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, 打开代码会发现非常简单 : 

Java代码  收藏代码
  1. public class InstrumentationSavingAgent {  
  2.   
  3.     private static volatile Instrumentation instrumentation;  
  4.   
  5.   
  6.     /** 
  7.      * Save the {@link Instrumentation} interface exposed by the JVM. 
  8.      */  
  9.     public static void premain(String agentArgs, Instrumentation inst) {  
  10.         instrumentation = inst;  
  11.     }  
  12.   
  13. }  



在 premain 方法里将 instrumentation 保存到 static 引用中以便后续访问. 

2. 配置 spring 支持 load time weaver 

Java代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.              xmlns:context="http://www.springframework.org/schema/context"  
  5.              xsi:schemaLocation="http://www.springframework.org/schema/beans  
  6.                                                 http://www.springframework.org/schema/beans/spring-beans.xsd  
  7.                                                 http://www.springframework.org/schema/context  
  8.                                                 http://www.springframework.org/schema/context/spring-context.xsd">  
  9.     <context:annotation-config />  
  10.     <context:load-time-weaver aspectj-weaving="on" />  
  11.       
  12.     <bean class="example.ltw.DefaultUserRepository" />  
  13.       
  14. </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 方法中 

Java代码  收藏代码
  1. protected boolean isAspectJWeavingEnabled(String value, ParserContext parserContext) {  
  2.     if ("on".equals(value)) {  
  3.         return true;  
  4.     }  
  5.     else if ("off".equals(value)) {  
  6.         return false;  
  7.     }  
  8.     else {  
  9.         // Determine default...  
  10.         ClassLoader cl = parserContext.getReaderContext().getResourceLoader().getClassLoader();  
  11.         return (cl.getResource(ASPECTJ_AOP_XML_RESOURCE) != null);  
  12.     }  
  13. }  



3. Code of User 

Java代码  收藏代码
  1. @Configurable(autowire = Autowire.BY_TYPE)  
  2. public class User {  
  3.       
  4.     @Resource  
  5.     // 或使用 @Autowired  
  6.     private UserRepository userRepository;  
  7.       
  8.     public void save() {  
  9.         userRepository.save(this);  
  10.     }  
  11.   
  12. }  




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 中 : 

Java代码  收藏代码
  1. public pointcut inConfigurableBean() : @this(Configurable);  
  2.   
  3. public pointcut preConstructionConfiguration() : preConstructionConfigurationSupport(*);   
  4.   
  5. declare parents: @Configurable * implements ConfigurableObject;  
  6.   
  7. public void configureBean(Object bean) {  
  8.  // 这里执行了 inject  
  9.     beanConfigurerSupport.configureBean(bean);  
  10. }  



附件是文中的示例项目, 运行 LoadTimeWeaverTest 即可. 

PS : Spring 也可以使用一些特定应用服务器的 ClassLoader 实现 LoadTimeWeaver, 如有兴趣请参考相应文档, 本文不再赘述. 

王政 于 2009, 10, 5 

分享到:
评论

相关推荐

    JDK8 下 SpringBoot 应用动态编译 Java 源码并注入 Spring 容器

    基于接口、抽象类实现不停机动态调整代码的目的,将修改后的源码文件放置于指定目录下,读取文件后执行动态编译方法,即可将该类重新加载,新的类可以在Spring容器从新注册,且仅在当前窗口生效。如果重启了服务或...

    Spring简单模拟Spring容器

    标题中的“Spring简单模拟Spring容器”意味着我们将探讨Spring框架的核心特性——IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入),以及如何通过编程方式模拟Spring容器的工作原理。...

    在非spring注解类中使用spring容器中的bean_普通类中使用yml配置文件中的配置信息

    然而,在某些情况下,我们可能需要在非Spring注解的类中访问Spring容器中的Bean,或者在这些类中使用YAML配置文件中的配置信息。本篇将详细介绍如何在这样的场景下实现这一目标。 首先,让我们来理解如何在非Spring...

    简单Spring容器实现

    - **依赖注入(Dependency Injection, DI)**:Spring的核心特性,它允许外部环境(如Spring容器)来管理对象的创建和依赖关系。DI通过反转控制权,使得组件之间松耦合,易于测试和维护。 - **Bean工厂(Bean ...

    Spring容器的通俗理解及简单写法

    在Java开发中,Spring容器(也称为ApplicationContext或BeanFactory)扮演着重要角色,它通过控制反转(Inversion of Control, IOC)和依赖注入(Dependency Injection, DI)的概念,帮助开发者构建松散耦合的系统。...

    spring IOC容器依赖注入XML配置

    这样,开发者无需在代码中手动创建和管理对象,而是由Spring容器负责,从而降低了耦合度。 XML配置是Spring早期的主要配置方式,虽然现在有注解配置和Java配置,但理解XML配置仍然是基础。一个基本的Spring配置文件...

    Spring容器 .ppt

    本篇内容将深入探讨Spring容器的基础、Bean的概念、依赖注入、Bean的范围、自定义接口、Bean定义的继承以及容器扩展点等重要知识点。 1. **简介** Spring容器是Spring框架的基石,主要分为两种类型:`BeanFactory`...

    获取Spring容器

    首先,在`spring-context.xml`中添加一个名为`ApplicationContextUtil`的Bean,该Bean用于实现`ApplicationContextAware`接口,以便Spring容器能够自动注入`ApplicationContext`。 ```xml ``` ##### 2. 实现`...

    深度解析spring容器管理bean

    "深度解析spring容器管理bean"这一主题,旨在深入理解Spring如何通过反射机制、依赖注入(DI)以及XML或Java配置来实现对Bean的生命周期管理。 首先,Spring容器主要有两种类型:DefaultListableBeanFactory和...

    spring容器简单实例

    本实例将带你深入理解Spring容器的基本使用,通过实际操作来帮助你快速上手。 1. **Spring容器概述** Spring容器是Spring框架的核心,负责管理对象的生命周期和依赖关系。主要有两种类型的容器:BeanFactory和...

    获取spring容器的方法

    这样,在Spring容器启动时,它会自动调用`setApplicationContext`方法,将`ApplicationContext`实例注入到实现了`ApplicationContextAware`的类中。 ### 结论 选择哪种方法获取Spring容器主要取决于具体的应用场景...

    spring 设值注入

    在Spring框架中,设值注入(Value Injection)是一种将外部属性值注入到bean对象中的方法。它是通过在bean的配置元数据中定义属性值来实现的,这些值会在bean实例化时自动设置。设值注入是Spring依赖注入...

    (转)Spring 3.0 注解注入详解

    3. **@Required**:此注解用在字段或setter方法上,表示该字段或方法必须通过依赖注入来设置,否则容器启动时会抛出异常。这通常用于强制确保某些关键依赖被正确地注入。 4. **@Value**:这个注解可以用于注入基本...

    spring依赖注入例子

    Spring框架的依赖注入(Dependency Injection,简称DI)是其核心特性之一,它使得对象之间的关系在运行时由Spring容器管理,而不是硬编码在类内部。这样可以提高代码的可测试性和可维护性,因为对象的依赖关系变得松...

    关于spring boot中几种注入方法的一些个人看法

    Spring Boot 中的几种注入方法 在 Spring Boot 中,注入是一种非常重要的机制,用于将 bean 对象注入到其他 bean 对象中,以便实现松耦合和高内聚的设计目标。下面我们将对 Spring Boot 中的几种注入方法进行详细的...

    Spring Ioc 注解 依赖注入

    - **依赖注入**:依赖注入是一种设计模式,通过依赖注入,一个类的对象不再负责创建其依赖的对象,而是由外部容器(Spring容器)来负责创建这些依赖并注入到需要它们的地方。 #### 三、Spring IoC容器的工作原理 ...

    spring的setter注入和构造注入(XML讲解以及常见错误)

    通过在类中定义setter方法,Spring容器可以在创建对象后,通过这些setter方法设置对象的属性值。以下是一个简单的例子: ```java public class User { private String name; public void setName(String name) {...

    Spring依赖注入检查.

    Spring依赖注入是Spring框架的核心特性之一,它极大地简化了Java应用程序的开发,使得对象之间的依赖关系得以解耦,提高了代码的可测试性和可维护性。本文将深入探讨Spring依赖注入的概念、工作原理以及如何在实际...

    Spring容器中IOC

    Spring容器中IOC Spring容器中IOC(Inverse of Control,控制反转)是Spring框架的核心功能之一。IOC容器是Spring Framework的核心组件之一,负责管理应用程序中的对象实例,控制对象的生命周期,并提供依赖注入的...

    Spring依赖注入使用构造设注入demo

    总结来说,Spring的构造器注入使我们能够明确地声明类的依赖,并让Spring容器负责管理和注入这些依赖,从而实现了低耦合和高内聚的设计。通过"SpringIOCTest2"这个示例,我们可以更好地理解和应用这一核心概念。

Global site tag (gtag.js) - Google Analytics