手动创建实例A a = new A()和自动创建实例@Autowired private A a;的区别

本文讨论了手动通过`new`关键字创建对象与使用`@Autowired`进行自动注入的两种方式,强调了手动创建对控制权的掌握,以及Spring容器在对象生命周期管理和依赖关系解决中的优势,提倡自动注入提高代码灵活性和可维护性。

对象的创建方式:
A a = new A():通过显式地使用 new 关键字创建 A 类的实例,即手动创建对象。
@Autowired private A a;:使用 @Autowired 注解自动将符合类型的 A 类的实例注入到 a 字段中,即自动创建对象。


对象的管理和生命周期:
A a = new A():手动创建的对象由开发者负责管理其生命周期,包括创建、销毁和依赖关系的维护。
@Autowired private A a;:自动注入的对象由 Spring 容器负责管理其生命周期,包括创建、销毁和依赖关系的解决。


控制权:
A a = new A():开发者完全掌握对象的创建和管理,可以在任何时候手动创建和销毁对象
@Autowired private A a;:开发者将对象的创建和管理权交给 Spring 容器,由容器自动创建和管理对象


依赖注入的灵活性:
A a = new A():手动创建对象时,对于依赖关系的解决需要开发者手动处理,可能会导致代码耦合性增加。
@Autowired private A a;:通过自动注入,Spring 容器会自动解决对象之间的依赖关系,减少了代码的耦合性。


总结:
A a = new A() 是手动创建对象的方式,开发者完全掌握对象的创建和管理。而 @Autowired private A a; 则是通过自动注入的方式,将对象的创建和管理交给 Spring 容器。自动注入可以提高代码的灵活性和可维护性,减少手动处理依赖关系的工作量。
 

### 问题明确 你希望在 `M3Service` 中通过 `@Autowired` 注入接口 `A`,但 `A` 有多个实现类(如 `C` 其他类),导致 Spring 无法确定注入哪一个实例,抛出 `NoUniqueBeanDefinitionException`。 --- ### 解决方案 #### 目标: 在 `M3Service` 中正确注入 `A` 的特定实现(如 `C`),同时保持 `m3()` 的 AOP 拦截能力。 #### 方法: 1. **使用 `@Qualifier` 指定具体实现**(推荐)。 2. **将 `M3Service` 设计为与 `C` 解耦**(更灵活)。 3. **通过构造函数注入并明确依赖**。 --- ### 方案 1:使用 `@Qualifier` 指定实现 如果 `C` 是 `A` 的主要实现,且你希望 `M3Service` 固定使用 `C`: #### 1. 修改 `M3Service` ```java @Component public class M3Service { @Autowired @Qualifier("c") // 指定注入名为"c"的Bean private A a; public void m3() { a.m1(); // 调用C的m1() System.out.println("M3Service.m3() 执行"); } } ``` #### 2. 确保 `C` 有明确的 Bean 名称 ```java @Component("c") // 显式命名Bean public class C extends B { @Override public void m1() { System.out.println("C实现了m1()"); } } ``` --- ### 方案 2:解耦 `M3Service` `C` 如果 `M3Service` 不应依赖具体的 `C`,而是需要动态选择 `A` 的实现: #### 1. 通过方法参数传递 `A` 的实例 ```java @Component public class M3Service { public void m3(A a) { // 由调用方传入具体的A实现 a.m1(); System.out.println("M3Service.m3() 执行"); } } ``` #### 2. 调用时传入具体实现 ```java @Component public class SomeService { @Autowired private M3Service m3Service; @Autowired private C c; // 直接注入C public void doSomething() { m3Service.m3(c); // 显式传入C的实例 } } ``` --- ### 方案 3:使用工厂或策略模式 如果 `A` 的实现需要根据运行时条件动态选择: #### 1. 定义工厂类 ```java @Component public class AFactory { @Autowired private List<A> allImplementations; // Spring会自动注入所有A的实现 public A getA(String type) { return allImplementations.stream() .filter(a -> a.getClass().getSimpleName().equals(type)) .findFirst() .orElseThrow(() -> new RuntimeException("未找到实现")); } } ``` #### 2. 修改 `M3Service` ```java @Component public class M3Service { @Autowired private AFactory aFactory; public void m3(String type) { A a = aFactory.getA(type); // 动态获取实现 a.m1(); } } ``` --- ### 关键点总结 1. **`@Qualifier` 的作用**: - 当接口有多个实现时,通过名称明确指定注入哪一个。 - 需确保目标 Bean 有唯一的名称(如 `@Component("c")`)。 2. **解耦设计**: - 如果 `M3Service` 不应绑定到 `C`,可通过参数或工厂动态传入 `A` 的实现。 3. **避免歧义性注入**: - 默认情况下,`@Autowired` 按类型注入,多个实现会报错。 - 解决方案包括:`@Qualifier`、`@Primary`、显式命名或解耦设计。 --- ### 推荐方案 **如果 `M3Service` 必须使用 `C` 的 `m1()`**: 使用 **方案 1(`@Qualifier`)**,明确指定注入 `C`。 **如果 `M3Service` 需要灵活性**: 使用 **方案 2(参数传递)** 或 **方案 3(工厂模式)**,解耦对 `C` 的依赖。 --- ### 最终代码示例(方案 1) ```java // 1. 定义接口实现 public interface A { void m1(); } @Component("c") // 显式命名 public class C implements A { @Override public void m1() { System.out.println("C实现了m1()"); } } // 2. 修改M3Service @Component public class M3Service { @Autowired @Qualifier("c") // 指定注入C private A a; public void m3() { a.m1(); // 调用C的m1() } } // 3. 定义切面 @Aspect @Component public class M3Aspect { @Before("execution(* com.example.M3Service.m3(..))") public void beforeM3() { System.out.println("AOP拦截了M3Service.m3()"); } } ``` --- ### 其他注意事项 1. **`@Primary` 注解**: - 如果某个实现应默认被注入,可标记为 `@Primary`: ```java @Primary @Component public class C implements A { ... } ``` - 这样无需 `@Qualifier`,Spring 会优先选择 `@Primary` 的实现。 2. **测试时的依赖注入**: - 在单元测试中,可通过 `@MockBean` 模拟特定的 `A` 实现: ```java @SpringBootTest public class M3ServiceTest { @MockBean @Qualifier("c") private A mockA; @Autowired private M3Service m3Service; @Test public void testM3() { m3Service.m3(); // 会调用mockA } } ``` --- ### 总结 - **明确依赖**:使用 `@Qualifier` 或 `@Primary` 解决多实现冲突。 - **解耦设计**:通过参数或工厂动态选择实现,提高灵活性。 - **测试友好**:确保设计便于模拟测试。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小懒懒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值