diff --git a/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/repository/UserRepository.java b/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/repository/UserRepository.java index f56c1b7..554ec9c 100644 --- a/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/repository/UserRepository.java +++ b/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/repository/UserRepository.java @@ -3,7 +3,7 @@ package com.xcs.spring.repository; import org.springframework.stereotype.Repository; /** - * @author 林雷 + * @author xcs * @date 2023年10月07日 11时51分 **/ @Repository diff --git a/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/service/AdminService.java b/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/service/AdminService.java index 4b439aa..f4f0484 100644 --- a/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/service/AdminService.java +++ b/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/service/AdminService.java @@ -3,7 +3,7 @@ package com.xcs.spring.service; import org.springframework.stereotype.Service; /** - * @author 林雷 + * @author xcs * @date 2023年10月07日 11时51分 **/ @Service diff --git a/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/service/UserService.java b/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/service/UserService.java index 4462cfd..5e34a8c 100644 --- a/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/service/UserService.java +++ b/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/service/UserService.java @@ -3,7 +3,7 @@ package com.xcs.spring.service; import org.springframework.stereotype.Service; /** - * @author 林雷 + * @author xcs * @date 2023年10月07日 11时50分 **/ @Service diff --git a/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/special/SpecialComponent.java b/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/special/SpecialComponent.java index c9d84cb..eab773b 100644 --- a/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/special/SpecialComponent.java +++ b/spring-annotation/spring-annotation-componentScan/src/main/java/com/xcs/spring/special/SpecialComponent.java @@ -1,7 +1,7 @@ package com.xcs.spring.special; /** - * @author 林雷 + * @author xcs * @date 2023年10月07日 11时52分 **/ public class SpecialComponent { diff --git a/spring-annotation/spring-annotation-dependsOn/src/main/java/com/xcs/spring/bean/BeanA.java b/spring-annotation/spring-annotation-dependsOn/src/main/java/com/xcs/spring/bean/BeanA.java index fbf039a..59a2f01 100644 --- a/spring-annotation/spring-annotation-dependsOn/src/main/java/com/xcs/spring/bean/BeanA.java +++ b/spring-annotation/spring-annotation-dependsOn/src/main/java/com/xcs/spring/bean/BeanA.java @@ -3,7 +3,7 @@ package com.xcs.spring.bean; import org.springframework.beans.factory.DisposableBean; /** - * @author 林雷 + * @author xcs * @date 2023年10月09日 16时45分 **/ public class BeanA implements DisposableBean { diff --git a/spring-annotation/spring-annotation-dependsOn/src/main/java/com/xcs/spring/bean/BeanB.java b/spring-annotation/spring-annotation-dependsOn/src/main/java/com/xcs/spring/bean/BeanB.java index 894735e..c262eb7 100644 --- a/spring-annotation/spring-annotation-dependsOn/src/main/java/com/xcs/spring/bean/BeanB.java +++ b/spring-annotation/spring-annotation-dependsOn/src/main/java/com/xcs/spring/bean/BeanB.java @@ -3,7 +3,7 @@ package com.xcs.spring.bean; import org.springframework.beans.factory.DisposableBean; /** - * @author 林雷 + * @author xcs * @date 2023年10月09日 16时46分 **/ public class BeanB implements DisposableBean { diff --git a/spring-annotation/spring-annotation-dependsOn/src/main/java/com/xcs/spring/bean/BeanC.java b/spring-annotation/spring-annotation-dependsOn/src/main/java/com/xcs/spring/bean/BeanC.java index 1553f54..4afcdda 100644 --- a/spring-annotation/spring-annotation-dependsOn/src/main/java/com/xcs/spring/bean/BeanC.java +++ b/spring-annotation/spring-annotation-dependsOn/src/main/java/com/xcs/spring/bean/BeanC.java @@ -3,7 +3,7 @@ package com.xcs.spring.bean; import org.springframework.beans.factory.DisposableBean; /** - * @author 林雷 + * @author xcs * @date 2023年10月09日 16时46分 **/ public class BeanC implements DisposableBean { diff --git a/spring-core/spring-core-resolveDependency/README.md b/spring-core/spring-core-resolveDependency/README.md index a16511d..05828f5 100644 --- a/spring-core/spring-core-resolveDependency/README.md +++ b/spring-core/spring-core-resolveDependency/README.md @@ -1 +1,358 @@ -## TODO \ No newline at end of file +### 一、基本信息 + +✒️ **作者** - Lex 📝 **博客** - [我的CSDN]() 📚 **文章目录** - [所有文章](https://github.com/xuchengsheng/spring-reading) + +### 二、方法描述 + +`resolveDependency` 是 Spring 框架中 `ConfigurableListableBeanFactory` 接口中定义的一个方法。这个方法的核心功能是解析并提供 bean 的依赖项。它主要在处理 `@Autowired` , `@Inject` ,`@Value`这样的自动装配场景时起作用。 + +### 三、方法源码 + +Spring IOC 容器中的一个核心方法,用于解析 bean 之间的依赖关系。当容器需要知道应该为特定的 bean、字段、构造函数或方法注入哪个其他 bean 时,就会调用这个方法。 + +```java +/** + * 在此工厂中定义的 beans 之间,解析指定的依赖项。 + * + * 该方法尝试匹配和返回一个适当的 bean 实例来满足给定的依赖描述符。 + * 依赖描述符可以描述字段、方法或构造函数中的依赖。 + * + * @param descriptor 描述依赖的对象,提供有关依赖类型、限定符等的详细信息。 + * @param requestingBeanName 声明或请求依赖的 bean 的名称。这通常用于解决 bean 之间的循环依赖。 + * @return 对应的 bean 实例以满足该依赖,如果没有合适的匹配,则返回 null。 + * + * @throws NoSuchBeanDefinitionException 当没有找到匹配的 bean 时抛出。 + * @throws NoUniqueBeanDefinitionException 当存在多个可能的匹配并且没有明确的选择时抛出。 + * @throws BeansException 如果由于其他原因解析失败则抛出。 + * + * @since 2.5 + * @see #resolveDependency(DependencyDescriptor, String, Set, TypeConverter) 用于更复杂的依赖解析场景,允许传递排除的 beans 和类型转换器。 + */ +@Nullable +Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException; +``` + +### 四、主要功能 + +1. **依赖描述符** + + 该方法接收一个 `DependencyDescriptor` 参数,它描述了所需的依赖关系。这个描述符可以表示一个字段、方法参数或构造函数参数的依赖。 +2. **自动装配限定符** + + 如果存在多个匹配的 bean,并且所需的依赖有 `@Autowired` 和 `@Qualifier` 注解,那么 `resolveDependency` 会考虑这些注解来确定正确的 bean。 +3. **解决循环依赖** + + 该方法也会考虑循环依赖的问题。例如,如果 Bean A 依赖于 Bean B,而 Bean B 又依赖于 Bean A,那么这种情况会被处理。 +4. **返回匹配的 bean** + + 此方法尝试返回一个与描述符匹配的 bean 实例。如果找不到合适的 bean,它可能返回 null 或抛出一个异常,具体取决于描述符的设置。 +5. **异常处理** + + 如果没有找到合适的 bean 或找到了多个合适的 bean 且没有明确的选择,该方法会抛出相应的异常。 +6. **其他 Considerations**: + - 可以考虑其他因素,如 `@Primary` 注解。 + - 对于基本类型或字符串类型的属性,可以解析 `@Value` 注解,从属性文件或环境变量中获取值。 + +### 五、最佳实践 + +首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。代码调用了两个方法(`methodResolveDependency` 和 `fieldResolveDependency`)来分别解析方法和字段的依赖。具体来说,它们会使用反射来获取目标方法或字段。创建一个描述这个方法或字段的 `DependencyDescriptor`。使用 `resolveDependency` 方法来从 Spring 容器中解析真正的依赖。使用反射来将解析得到的依赖注入到目标对象中。在解析方法和字段的依赖之后,代码通过格式化的字符串打印了相关信息。例如,它显示了方法或字段的完全限定名称和解析得到的依赖对象的值。 + +```java +public class ResolveDependencyApplication { + + public static void main(String[] args) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class); + // 获得Bean工厂 + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + // 被注入对象 + MyServiceB injectTarget = new MyServiceB(); + + System.out.println("Before MyServiceB = " + injectTarget + "\n"); + + methodResolveDependency(beanFactory, injectTarget, "setMethodMyServiceA"); + fieldResolveDependency(beanFactory, injectTarget, "fieldMyServiceA"); + fieldResolveDependency(beanFactory, injectTarget, "myPropertyValue"); + + System.out.println("After MyServiceB = " + injectTarget + "\n"); + } + + /** + * 解析方法依赖 + * + * @param beanFactory + * @param injectTarget + */ + public static void methodResolveDependency(ConfigurableListableBeanFactory beanFactory, Object injectTarget, String name) { + try { + // 1. 获取MyServiceB类中名为setMyServiceA的方法的引用 + Method method = injectTarget.getClass().getMethod(name, MyServiceA.class); + + // 2. 创建一个描述此方法参数的DependencyDescriptor + DependencyDescriptor desc = new DependencyDescriptor(new MethodParameter(method, 0), true); + + // 3. 使用BeanFactory来解析这个方法参数的依赖 + Object value = beanFactory.resolveDependency(desc, null); + + System.out.println("解析方法依赖结果:"); + System.out.println("---------------------------------------------"); + System.out.println(String.format("Name: %s.%s",method.getDeclaringClass().getName(),method.getName())); + System.out.println(String.format("Value: %s", value)); + System.out.println("---------------------------------------------\n"); + + // 4. 使方法可访问(特别是如果它是private的) + ReflectionUtils.makeAccessible(method); + + // 5. 使用反射调用这个方法,将解析得到的依赖注入到目标对象中 + method.invoke(injectTarget, value); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 解析字段依赖 + * + * @param beanFactory + * @param injectTarget + */ + public static void fieldResolveDependency(ConfigurableListableBeanFactory beanFactory, Object injectTarget, String name) { + try { + // 1. 获取MyServiceB类中名为fieldMyServiceA的字段的引用 + Field field = injectTarget.getClass().getDeclaredField(name); + + // 2. 创建一个描述此字段的DependencyDescriptor + DependencyDescriptor desc = new DependencyDescriptor(field, true); + + // 3. 使用BeanFactory来解析这个字段的依赖 + Object value = beanFactory.resolveDependency(desc, null); + + System.out.println("解析字段依赖结果:"); + System.out.println("---------------------------------------------"); + System.out.println(String.format("Name: %s.%s", field.getDeclaringClass().getName(), field.getName())); + System.out.println(String.format("Value: %s", value)); + System.out.println("---------------------------------------------\n"); + + // 4. 使字段可访问(特别是如果它是private的) + ReflectionUtils.makeAccessible(field); + + // 5. 使用反射设置这个字段的值,将解析得到的依赖注入到目标对象中 + field.set(injectTarget, value); + } catch (Exception e) { + e.printStackTrace(); + } + } +} +``` + +在`MyConfiguration`类中,使用了`@ComponentScan("com.xcs.spring")`注解告诉 Spring 在指定的包(在这里是 "`com.xcs.spring`")及其子包中搜索带有 `@Component`、`@Service`、`@Repository` 和 `@Controller` 等注解的类,并将它们自动注册为 beans。这样,spring就不必为每个组件明确写一个 bean 定义。Spring 会自动识别并注册它们。另外使用`@PropertySource`注解从类路径下的`application.properties`文件中加载属性。 + +```java +@Configuration +@ComponentScan("com.xcs.spring") +@PropertySource("classpath:application.properties") +public class MyConfiguration { + +} +``` + +`application.properties`文件在`src/main/resources`目录中,并添加以下内容。 + +```properties +my.property.value = Hello from Environment! +``` + +`MyService` 是一个简单的服务类,但我们没有定义任何方法或功能。 + +```java +@Service +public class MyServiceA { + +} +``` + +首先 `MyServiceB` 没有被 Spring 托管,那么它在代码中的表现就与一个普通的 Java 类没有什么不同。虽然 `MyServiceB` 本身不是 Spring 托管的,但 `ResolveDependencyApplication` 类中,我给大家展示了如何使用 Spring 的底层 API 手动解析和注入依赖。 + +- **字段 `myPropertyValue`** + + 虽然它有一个 `@Value` 注解,但由于 `MyServiceB` 不是一个 Spring 管理的 bean,所以这个注解不会自动被解析。 +- **字段 `myServiceA` 和 `fieldMyServiceA`** + + 由于没有自动的 Spring 依赖注入,这两个字段默认为 `null`。 +- **方法 `setMyServiceA`** + + 这是一个普通的 setter 方法。但在 `MyServiceB` 不被 Spring 托管的情况下,它只是一个普通的 setter。 +- **方法 `toString`** + + 该方法为该类提供了一个自定义的字符串表示。这与 `MyServiceB` 是否被 Spring 托管无关。 + +```java +public class MyServiceB { + + /** + * 方法注入 + */ + private MyServiceA methodMyServiceA; + + /** + * 字段注入 + */ + private MyServiceA fieldMyServiceA; + + /** + * 字段注入 (环境变量) + */ + @Value("${my.property.value}") + private String myPropertyValue; + + public void setMethodMyServiceA(MyServiceA methodMyServiceA){ + this.methodMyServiceA = methodMyServiceA; + } + + @Override + public String toString() { + return "MyServiceB{" + + "myPropertyValue='" + myPropertyValue + '\'' + + ", methodMyServiceA=" + methodMyServiceA + + ", fieldMyServiceA=" + fieldMyServiceA + + '}'; + } +} +``` + +运行结果发现,使用了 Spring 的底层 `resolveDependency` 方法来为 `MyServiceB` 类的字段和方法手动注入依赖。虽然在常规的 Spring 开发中我们通常不这样做(因为 Spring 提供了更高级的自动化工具进行依赖注入),但这主要目的是给大家展示 Spring 如何在底层工作原理,并提供了一种手动控制依赖注入的方法。 + +```java +Before MyServiceB = MyServiceB{myPropertyValue='null', myServiceA=null, fieldMyServiceA=null} + +解析方法依赖结果: +--------------------------------------------- +Name: com.xcs.spring.service.MyServiceB.setMyServiceA +Value: com.xcs.spring.service.MyServiceA@202b0582 +--------------------------------------------- + +解析字段依赖结果: +--------------------------------------------- +Name: com.xcs.spring.service.MyServiceB.fieldMyServiceA +Value: com.xcs.spring.service.MyServiceA@202b0582 +--------------------------------------------- + +解析字段依赖结果: +--------------------------------------------- +Name: com.xcs.spring.service.MyServiceB.myPropertyValue +Value: Hello from Environment! +--------------------------------------------- + +After MyServiceB = MyServiceB{myPropertyValue='Hello from Environment!', myServiceA=com.xcs.spring.service.MyServiceA@202b0582, fieldMyServiceA=com.xcs.spring.service.MyServiceA@202b0582} + +``` + +### 六、时序图 + +#### 环境属性和变量 + +通过使用`@Value`注解,我们可以请求一个特定的环境属性或变量。例如,我们可能会这样请求一个名为`my.property.value`的属性。 + +~~~mermaid +sequenceDiagram +Title: resolveDependency方法解析环境属性和变量时序图 + +ResolveDependencyApplication-->>AbstractAutowireCapableBeanFactory:resolveDependency(descriptor,requestingBeanName) +note over AbstractAutowireCapableBeanFactory: 请求解析依赖 + +AbstractAutowireCapableBeanFactory->>DefaultListableBeanFactory:resolveDependency(descriptor, requestingBeanName, null, null) +note over DefaultListableBeanFactory: 转到具体的Bean工厂进行解析 + +DefaultListableBeanFactory->>DefaultListableBeanFactory:doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter) +note over DefaultListableBeanFactory: 进行实际的依赖解析 + +DefaultListableBeanFactory->>DefaultListableBeanFactory:getAutowireCandidateResolver() +note over DefaultListableBeanFactory: 获取当前的依赖解析策略 + +DefaultListableBeanFactory->>QualifierAnnotationAutowireCandidateResolver:getSuggestedValue(descriptor) +note over QualifierAnnotationAutowireCandidateResolver: 基于给定的描述符查找建议的值 + +QualifierAnnotationAutowireCandidateResolver->>QualifierAnnotationAutowireCandidateResolver:findValue(annotationsToSearch) +note over QualifierAnnotationAutowireCandidateResolver: 在指定的注解中寻找值 + +QualifierAnnotationAutowireCandidateResolver->>QualifierAnnotationAutowireCandidateResolver:extractValue(attr) +note over QualifierAnnotationAutowireCandidateResolver: 从注解属性中提取值 + +QualifierAnnotationAutowireCandidateResolver->>DefaultListableBeanFactory:返回@Value注解的表达式 +note over DefaultListableBeanFactory: 解析注解中的表达式或值 + +DefaultListableBeanFactory->>AbstractBeanFactory:resolveEmbeddedValue(value) +note over AbstractBeanFactory: 解析嵌入的值(如占位符或SpEL表达式) + +DefaultListableBeanFactory->>AbstractBeanFactory:evaluateBeanDefinitionString(strVal, bd) +note over AbstractBeanFactory: 对bean定义字符串进行评估(可能是一个表达式) + +DefaultListableBeanFactory->>AbstractBeanFactory:getTypeConverter() +note over AbstractBeanFactory: 获取用于类型转换的转换器 + +DefaultListableBeanFactory->>TypeConverterSupport:convertIfNecessary(value, type, typeDescriptor()) +note over TypeConverterSupport: 根据需要将值转换为指定的类型 + +TypeConverterSupport->>DefaultListableBeanFactory:返回类型转换的结果 +note over DefaultListableBeanFactory: 用转换后的值继续解析流程 + +DefaultListableBeanFactory->>AbstractAutowireCapableBeanFactory:返回环境属性 +AbstractAutowireCapableBeanFactory->>ResolveDependencyApplication:返回环境属性 +~~~ + +#### Bean依赖 + +这是其主要的功能。当我们有一个bean,它需要另一个bean的实例时,`resolveDependency` 会为我们找到并提供所需的bean。例如,如果一个`MyServiceB`类需要一个`MyServiceA`类的实例,那么`resolveDependency` 可以为`MyServiceB`类提供一个`MyServiceA`的实例。 + +~~~mermaid +sequenceDiagram +Title: resolveDependency方法解析Bean依赖时序图 + +ResolveDependencyApplication-->>AbstractAutowireCapableBeanFactory:resolveDependency(descriptor,requestingBeanName) +note right of AbstractAutowireCapableBeanFactory: 开始解析依赖请求 + +AbstractAutowireCapableBeanFactory->>DefaultListableBeanFactory:resolveDependency(descriptor, requestingBeanName, null, null) +note right of DefaultListableBeanFactory: 委托给具体的Bean工厂进行依赖解析 + +DefaultListableBeanFactory->>DefaultListableBeanFactory:doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter) +note right of DefaultListableBeanFactory: 执行具体的依赖解析逻辑 + +DefaultListableBeanFactory->>DefaultListableBeanFactory:resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter) +note right of DefaultListableBeanFactory: 解析满足条件的多个Beans + +DefaultListableBeanFactory->>DefaultListableBeanFactory:findAutowireCandidates(beanName, type, descriptor) +note right of DefaultListableBeanFactory: 查找适合自动装配的候选Beans + +DefaultListableBeanFactory->>DefaultListableBeanFactory:isSelfReference(beanName, candidate) +note right of DefaultListableBeanFactory: 检查bean是否引用了自身 + +DefaultListableBeanFactory->>DefaultListableBeanFactory:isAutowireCandidate(candidate, descriptor) +note right of DefaultListableBeanFactory: 检查bean是否是一个合适的自动装配候选 + +DefaultListableBeanFactory->>DefaultListableBeanFactory:addCandidateEntry(result, candidate, descriptor, requiredType) +note right of DefaultListableBeanFactory: 将找到的候选添加到结果集中 + +DefaultListableBeanFactory->>DependencyDescriptor:resolveCandidate(candidateName, requiredType, beanFactory) +note right of DependencyDescriptor: 尝试解析并返回候选Bean + +DependencyDescriptor->>AbstractBeanFactory:getBean(String name) +note right of AbstractBeanFactory: 请求获取指定名称的bean + +AbstractBeanFactory->>DependencyDescriptor:返回候选的Bean对象 +note right of DependencyDescriptor: 返回找到的Bean实例 + +DependencyDescriptor->>DefaultListableBeanFactory:返回候选的Bean对象 +note right of DefaultListableBeanFactory: 将Bean实例返回给Bean工厂 + +DefaultListableBeanFactory->>DefaultListableBeanFactory:determineAutowireCandidate(matchingBeans, descriptor) +note right of DefaultListableBeanFactory: 从匹配的Beans中确定自动装配的候选 + +DefaultListableBeanFactory->>AbstractAutowireCapableBeanFactory:返回Bean +note right of AbstractAutowireCapableBeanFactory: 将确定的Bean返回给上一级的Bean工厂 + +AbstractAutowireCapableBeanFactory->>ResolveDependencyApplication:返回bean +note right of ResolveDependencyApplication: 返回bean给依赖解析的请求者 + +~~~ + + + +### 七、源码分析 + +### 八、注意事项 + +### 九、总结 + +#### 最佳实践总结 + +#### 源码分析总结 \ No newline at end of file diff --git a/spring-core/spring-core-resolveDependency/src/main/java/com/xcs/spring/ResolveDependencyApplication.java b/spring-core/spring-core-resolveDependency/src/main/java/com/xcs/spring/ResolveDependencyApplication.java new file mode 100644 index 0000000..a4568c4 --- /dev/null +++ b/spring-core/spring-core-resolveDependency/src/main/java/com/xcs/spring/ResolveDependencyApplication.java @@ -0,0 +1,102 @@ +package com.xcs.spring; + +import com.xcs.spring.config.MyConfiguration; +import com.xcs.spring.service.MyServiceA; +import com.xcs.spring.service.MyServiceB; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.DependencyDescriptor; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.core.MethodParameter; +import org.springframework.util.ReflectionUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * @author xcs + * @date 2023年10月25日 10时13分 + **/ +public class ResolveDependencyApplication { + + public static void main(String[] args) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class); + // 获得Bean工厂 + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + // 被注入对象 + MyServiceB injectTarget = new MyServiceB(); + + System.out.println("Before MyServiceB = " + injectTarget + "\n"); + + methodResolveDependency(beanFactory, injectTarget, "setMethodMyServiceA"); + fieldResolveDependency(beanFactory, injectTarget, "fieldMyServiceA"); + fieldResolveDependency(beanFactory, injectTarget, "myPropertyValue"); + + System.out.println("After MyServiceB = " + injectTarget + "\n"); + } + + /** + * 解析方法依赖 + * + * @param beanFactory + * @param injectTarget + */ + public static void methodResolveDependency(ConfigurableListableBeanFactory beanFactory, Object injectTarget, String name) { + try { + // 1. 获取MyServiceB类中名为setMyServiceA的方法的引用 + Method method = injectTarget.getClass().getMethod(name, MyServiceA.class); + + // 2. 创建一个描述此方法参数的DependencyDescriptor + DependencyDescriptor desc = new DependencyDescriptor(new MethodParameter(method, 0), true); + + // 3. 使用BeanFactory来解析这个方法参数的依赖 + Object value = beanFactory.resolveDependency(desc, null); + + System.out.println("解析方法依赖结果:"); + System.out.println("---------------------------------------------"); + System.out.println(String.format("Name: %s.%s",method.getDeclaringClass().getName(),method.getName())); + System.out.println(String.format("Value: %s", value)); + System.out.println("---------------------------------------------\n"); + + // 4. 使方法可访问(特别是如果它是private的) + ReflectionUtils.makeAccessible(method); + + // 5. 使用反射调用这个方法,将解析得到的依赖注入到目标对象中 + method.invoke(injectTarget, value); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 解析字段依赖 + * + * @param beanFactory + * @param injectTarget + */ + public static void fieldResolveDependency(ConfigurableListableBeanFactory beanFactory, Object injectTarget, String name) { + try { + // 1. 获取MyServiceB类中名为fieldMyServiceA的字段的引用 + Field field = injectTarget.getClass().getDeclaredField(name); + + // 2. 创建一个描述此字段的DependencyDescriptor + DependencyDescriptor desc = new DependencyDescriptor(field, true); + + // 3. 使用BeanFactory来解析这个字段的依赖 + Object value = beanFactory.resolveDependency(desc, null); + + System.out.println("解析字段依赖结果:"); + System.out.println("---------------------------------------------"); + System.out.println(String.format("Name: %s.%s", field.getDeclaringClass().getName(), field.getName())); + System.out.println(String.format("Value: %s", value)); + System.out.println("---------------------------------------------\n"); + + // 4. 使字段可访问(特别是如果它是private的) + ReflectionUtils.makeAccessible(field); + + // 5. 使用反射设置这个字段的值,将解析得到的依赖注入到目标对象中 + field.set(injectTarget, value); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/spring-core/spring-core-resolveDependency/src/main/java/com/xcs/spring/config/MyConfiguration.java b/spring-core/spring-core-resolveDependency/src/main/java/com/xcs/spring/config/MyConfiguration.java new file mode 100644 index 0000000..cc63529 --- /dev/null +++ b/spring-core/spring-core-resolveDependency/src/main/java/com/xcs/spring/config/MyConfiguration.java @@ -0,0 +1,15 @@ +package com.xcs.spring.config; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +/** + * @author xcs + * @date 2023年09月19日 16时35分 + **/ +@Configuration +@ComponentScan("com.xcs.spring") +@PropertySource("classpath:application.properties") +public class MyConfiguration { +} diff --git a/spring-core/spring-core-resolveDependency/src/main/java/com/xcs/spring/service/MyServiceA.java b/spring-core/spring-core-resolveDependency/src/main/java/com/xcs/spring/service/MyServiceA.java new file mode 100644 index 0000000..c0582d3 --- /dev/null +++ b/spring-core/spring-core-resolveDependency/src/main/java/com/xcs/spring/service/MyServiceA.java @@ -0,0 +1,12 @@ +package com.xcs.spring.service; + +import org.springframework.stereotype.Service; + +/** + * @author xcs + * @date 2023年10月25日 10时36分 + **/ +@Service +public class MyServiceA { + +} diff --git a/spring-core/spring-core-resolveDependency/src/main/java/com/xcs/spring/service/MyServiceB.java b/spring-core/spring-core-resolveDependency/src/main/java/com/xcs/spring/service/MyServiceB.java new file mode 100644 index 0000000..1907a5c --- /dev/null +++ b/spring-core/spring-core-resolveDependency/src/main/java/com/xcs/spring/service/MyServiceB.java @@ -0,0 +1,39 @@ +package com.xcs.spring.service; + +import org.springframework.beans.factory.annotation.Value; + +/** + * @author xcs + * @date 2023年10月25日 10时37分 + **/ +public class MyServiceB { + + /** + * 方法注入 + */ + private MyServiceA methodMyServiceA; + + /** + * 字段注入 + */ + private MyServiceA fieldMyServiceA; + + /** + * 字段注入 (环境变量) + */ + @Value("${my.property.value}") + private String myPropertyValue; + + public void setMethodMyServiceA(MyServiceA methodMyServiceA){ + this.methodMyServiceA = methodMyServiceA; + } + + @Override + public String toString() { + return "MyServiceB{" + + "myPropertyValue='" + myPropertyValue + '\'' + + ", methodMyServiceA=" + methodMyServiceA + + ", fieldMyServiceA=" + fieldMyServiceA + + '}'; + } +} diff --git a/spring-core/spring-core-resolveDependency/src/main/resources/application.properties b/spring-core/spring-core-resolveDependency/src/main/resources/application.properties new file mode 100644 index 0000000..2f49904 --- /dev/null +++ b/spring-core/spring-core-resolveDependency/src/main/resources/application.properties @@ -0,0 +1 @@ +my.property.value = Hello from Environment! \ No newline at end of file diff --git a/spring-interface/spring-interface-mergedBeanDefinitionPostProcessor/src/main/java/com/xcs/spring/bean/MyBean.java b/spring-interface/spring-interface-mergedBeanDefinitionPostProcessor/src/main/java/com/xcs/spring/bean/MyBean.java index 9db1660..7b9c900 100644 --- a/spring-interface/spring-interface-mergedBeanDefinitionPostProcessor/src/main/java/com/xcs/spring/bean/MyBean.java +++ b/spring-interface/spring-interface-mergedBeanDefinitionPostProcessor/src/main/java/com/xcs/spring/bean/MyBean.java @@ -3,7 +3,7 @@ package com.xcs.spring.bean; import com.xcs.spring.annotation.MyValue; /** - * @author 林雷 + * @author xcs * @date 2023年09月20日 10时52分 **/ public class MyBean { diff --git a/spring-interface/spring-interface-smartInitializingSingleton/src/main/java/com/xcs/spring/service/MyService.java b/spring-interface/spring-interface-smartInitializingSingleton/src/main/java/com/xcs/spring/service/MyService.java index 55e0a54..6ac0a85 100644 --- a/spring-interface/spring-interface-smartInitializingSingleton/src/main/java/com/xcs/spring/service/MyService.java +++ b/spring-interface/spring-interface-smartInitializingSingleton/src/main/java/com/xcs/spring/service/MyService.java @@ -6,7 +6,7 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; /** - * @author 林雷 + * @author xcs * @date 2023年09月27日 10时36分 **/ @Service diff --git a/spring-interface/spring-interface-smartInstantiationAwareBeanPostProcessor/src/main/java/com/xcs/spring/service/MyService.java b/spring-interface/spring-interface-smartInstantiationAwareBeanPostProcessor/src/main/java/com/xcs/spring/service/MyService.java index 78b9e61..95030a9 100644 --- a/spring-interface/spring-interface-smartInstantiationAwareBeanPostProcessor/src/main/java/com/xcs/spring/service/MyService.java +++ b/spring-interface/spring-interface-smartInstantiationAwareBeanPostProcessor/src/main/java/com/xcs/spring/service/MyService.java @@ -4,7 +4,7 @@ import com.xcs.spring.annotation.MyAutowired; import org.springframework.stereotype.Component; /** - * @author 林雷 + * @author xcs * @date 2023年09月21日 10时31分 **/ @Component diff --git a/spring-jsr/spring-jsr250-postConstruct/src/main/java/com/xcs/spring/PostConstructApplication.java b/spring-jsr/spring-jsr250-postConstruct/src/main/java/com/xcs/spring/PostConstructApplication.java index 524ac25..e41b810 100644 --- a/spring-jsr/spring-jsr250-postConstruct/src/main/java/com/xcs/spring/PostConstructApplication.java +++ b/spring-jsr/spring-jsr250-postConstruct/src/main/java/com/xcs/spring/PostConstructApplication.java @@ -4,7 +4,7 @@ import com.xcs.spring.config.MyConfiguration; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** - * @author 林雷 + * @author xcs * @date 2023年10月18日 14时17分 **/ public class PostConstructApplication { diff --git a/spring-jsr/spring-jsr250-preDestroy/src/main/java/com/xcs/spring/PreDestroyApplication.java b/spring-jsr/spring-jsr250-preDestroy/src/main/java/com/xcs/spring/PreDestroyApplication.java index bd4d8fb..d68bd87 100644 --- a/spring-jsr/spring-jsr250-preDestroy/src/main/java/com/xcs/spring/PreDestroyApplication.java +++ b/spring-jsr/spring-jsr250-preDestroy/src/main/java/com/xcs/spring/PreDestroyApplication.java @@ -4,7 +4,7 @@ import com.xcs.spring.config.MyConfiguration; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** - * @author 林雷 + * @author xcs * @date 2023年10月18日 14时17分 **/ public class PreDestroyApplication { diff --git a/spring-jsr/spring-jsr330-named/src/main/java/com/xcs/spring/service/MyService.java b/spring-jsr/spring-jsr330-named/src/main/java/com/xcs/spring/service/MyService.java index 786207f..ec03de2 100644 --- a/spring-jsr/spring-jsr330-named/src/main/java/com/xcs/spring/service/MyService.java +++ b/spring-jsr/spring-jsr330-named/src/main/java/com/xcs/spring/service/MyService.java @@ -1,7 +1,7 @@ package com.xcs.spring.service; /** - * @author 林雷 + * @author xcs * @date 2023年10月19日 16时44分 **/ public class MyService { diff --git a/spring-jsr/spring-jsr330-named/src/main/java/com/xcs/spring/service/MyServiceA.java b/spring-jsr/spring-jsr330-named/src/main/java/com/xcs/spring/service/MyServiceA.java index 02a564a..41d0558 100644 --- a/spring-jsr/spring-jsr330-named/src/main/java/com/xcs/spring/service/MyServiceA.java +++ b/spring-jsr/spring-jsr330-named/src/main/java/com/xcs/spring/service/MyServiceA.java @@ -3,7 +3,7 @@ package com.xcs.spring.service; import javax.inject.Named; /** - * @author 林雷 + * @author xcs * @date 2023年10月19日 16时43分 **/ @Named("myServiceA") diff --git a/spring-jsr/spring-jsr330-named/src/main/java/com/xcs/spring/service/MyServiceB.java b/spring-jsr/spring-jsr330-named/src/main/java/com/xcs/spring/service/MyServiceB.java index 6b782f9..d13d480 100644 --- a/spring-jsr/spring-jsr330-named/src/main/java/com/xcs/spring/service/MyServiceB.java +++ b/spring-jsr/spring-jsr330-named/src/main/java/com/xcs/spring/service/MyServiceB.java @@ -3,7 +3,7 @@ package com.xcs.spring.service; import javax.inject.Named; /** - * @author 林雷 + * @author xcs * @date 2023年10月19日 16时43分 **/ @Named("myServiceB") diff --git a/spring-jsr/spring-jsr330-provider/src/main/java/com/xcs/spring/service/MyService.java b/spring-jsr/spring-jsr330-provider/src/main/java/com/xcs/spring/service/MyService.java index cf6498d..71b1ed8 100644 --- a/spring-jsr/spring-jsr330-provider/src/main/java/com/xcs/spring/service/MyService.java +++ b/spring-jsr/spring-jsr330-provider/src/main/java/com/xcs/spring/service/MyService.java @@ -4,7 +4,7 @@ import org.springframework.stereotype.Service; /** - * @author 林雷 + * @author xcs * @date 2023年10月19日 16时44分 **/ @Service diff --git a/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/QualifierApplication.java b/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/QualifierApplication.java index 5143d9d..9280c64 100644 --- a/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/QualifierApplication.java +++ b/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/QualifierApplication.java @@ -5,7 +5,7 @@ import com.xcs.spring.controller.MessageController; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** - * @author 林雷 + * @author xcs * @date 2023年10月20日 14时56分 **/ public class QualifierApplication { diff --git a/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/config/MyConfiguration.java b/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/config/MyConfiguration.java index cbccc6d..3ad22f9 100644 --- a/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/config/MyConfiguration.java +++ b/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/config/MyConfiguration.java @@ -4,7 +4,7 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; /** - * @author 林雷 + * @author xcs * @date 2023年10月20日 14时56分 **/ @Configuration diff --git a/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/controller/MessageController.java b/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/controller/MessageController.java index 6e6411c..7a76047 100644 --- a/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/controller/MessageController.java +++ b/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/controller/MessageController.java @@ -8,7 +8,7 @@ import org.springframework.stereotype.Controller; import javax.inject.Inject; /** - * @author 林雷 + * @author xcs * @date 2023年10月20日 14时59分 **/ @Controller diff --git a/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/service/MessageService.java b/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/service/MessageService.java index c644723..832dc15 100644 --- a/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/service/MessageService.java +++ b/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/service/MessageService.java @@ -1,7 +1,7 @@ package com.xcs.spring.service; /** - * @author 林雷 + * @author xcs * @date 2023年10月20日 14时56分 **/ public interface MessageService { diff --git a/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/service/impl/EmailServiceImpl.java b/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/service/impl/EmailServiceImpl.java index 2381379..ec984c3 100644 --- a/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/service/impl/EmailServiceImpl.java +++ b/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/service/impl/EmailServiceImpl.java @@ -6,7 +6,7 @@ import com.xcs.spring.service.MessageService; import javax.inject.Named; /** - * @author 林雷 + * @author xcs * @date 2023年10月20日 14时57分 **/ @Email diff --git a/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/service/impl/SMSServiceImpl.java b/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/service/impl/SMSServiceImpl.java index 1c780bf..0fe05d7 100644 --- a/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/service/impl/SMSServiceImpl.java +++ b/spring-jsr/spring-jsr330-qualifier/src/main/java/com/xcs/spring/service/impl/SMSServiceImpl.java @@ -6,7 +6,7 @@ import com.xcs.spring.service.MessageService; import javax.inject.Named; /** - * @author 林雷 + * @author xcs * @date 2023年10月20日 14时57分 **/ @SMS