在Pro Spring 3 Book中,第4章 - 介绍IOC和DI在春天 - 第59页,在"Setter Injection vs. Constructor Injection"部分,一段说
包含Spring,提供了一种机制,用于确保在使用Setter Injection时定义所有依赖项,但是通过使用Constructor Injection,您可以以容器无关的方式声明对依赖项的要求"
你能解释一下例子吗?
对于Spring Boot应用程序,我LdapTemplate使用注释成功配置了Spring ,包括LdapContextSource与@Valueapplication.properties中的s 的依赖关系.(哇!我找不到一个例子,所以也许这会帮助别人.)
片段(下面)设置上下文源,将其注入LdapTemplate到我的DirectoryService中,然后自动装入到我的DirectoryService中.
是否有更好/更清晰的方法来设置ContextSourceSpring Boot应用程序?
application.properties(在类路径上):
ldap.url=ldap://server.domain.com:389
ldap.base:OU=Employees,OU=Users,DC=domain,DC=com
ldap.username:CN=myuserid,OU=employees,OU=Users,DC=domain,DC=com
ldap.password:secretthingy
Run Code Online (Sandbox Code Playgroud)
MyLdapContextSource.java:
@Component
public class MyLdapContextSource extends LdapContextSource implements ContextSource {
@Value("${ldap.url}")
@Override
public void setUrl(String url) { super.setUrl(url); }
@Value("${ldap.base}")
@Override
public void setBase(String base) {super.setBase(base); }
@Value("${ldap.username}")
@Override
public void setUserDn(String userDn) {super.setUserDn(userDn); }
@Value("${ldap.password}")
@Override
public void setPassword(String password) { super.setPassword(password); }
}
Run Code Online (Sandbox Code Playgroud)
MyLdapTemplate.java:
@Component
public class MyLdapTemplate extends LdapTemplate {
@Autowired
public MyLdapTemplate(ContextSource …Run Code Online (Sandbox Code Playgroud) 弹簧有两种类型的DI:定位器DI和结构DI.
基于构造函数的DI修复了需要注入依赖项的顺序.基于Setter的DI不提供此功能.
基于Setter的DI帮助我们仅在需要时注入依赖项,而不是在构造时需要它.
我没有看到任何其他显着差异,因为两种类型的Spring DI都提供相同的功能 - 设置器和构造函数DI在代码启动时注入依赖关系.当然,构造函数DI将通过构造函数执行,而setter DI将在构造对象后立即通过setter执行它,但它在性能等方面对开发人员没有任何影响.两者都提供了指定顺序的方法依赖注入也是如此.
我正在寻找一个场景,其中一个提供明显优势,或一个类型完全无法使用.
我读到(例如此处),如果我使用字段依赖项注入,那么我无法创建不可变对象,但我不明白字段依赖项注入如何破坏不可变性,我可以执行如下操作可以创建不可变对象SpringTest,不是吗?
@Component
public final class SpringTest {
@Autowired
private Person person;
// here I will have no setter methods exposing "person" object but will only have getter methods for "person" object, ensuring defensive copying etc...
}
Run Code Online (Sandbox Code Playgroud)
更新:请注意,我的问题特别是关于字段注入破坏不变性,所以我想知道我的上面的代码片段(自我最初的问题以来发生了变化,感谢@Andy和其他人纠正它)是如何破坏不变性的,我认为事实并非如此,所以我认为这个关于字段注入不变性的答案是错误的。
我通常在其他代码中看到使用final关键字将Service Bean注入到控制器中,有些代码则没有。那么,这里使用“final”的原因是什么?我知道最终变量意味着它是不可变变量。我研究了一些博客,他们说这与线程安全有关。
我是吉斯的新手。首选构造函数注入还是首选字段注入?
现场注入似乎快速而简单,但由于缺少构造函数,测试将是一个挑战。
谢谢。
谁能告诉我为什么@autowired 说不推荐字段注入,并且 TextWriter 对象“text”也说它不能自动装配,因为有不止一个 textwriter 类型的 bean。我的代码。
我有一个在此类中创建的类,new B(this);BI 希望使用 application.properties 中的值。但是因为(据我所知)因为它不是用 Spring 创建的,所以不会有任何注入(我使用注释@Value)
这就是类的创建方式:
@Component
public class A {
public B getB(){return new B(this);}
/**
a lot more stuff
**/
}
Run Code Online (Sandbox Code Playgroud)
有问题的班级:
public class B {
private A a;
public B(A a){
this.a = a;
}
@Value("${threshold}")
private String threshold; //this is null because it's not created with Spring
public String getThreshold(){
return threshold;
}
/**
a lot more stuff
**/
}
Run Code Online (Sandbox Code Playgroud)
所以我的问题如下:
1)如何使用 application.properties 文件中的值或
2)B怎么写,它是用Spring创建的?
一些背景信息:
正如标题所示,我想知道字段注入在 Spring 内部是如何工作的,我阅读了很多关于此的文章并了解了如下内容,但不明白其背后的确切原因:
-> 不应该使用它,因为当您进行单元测试时,您依赖于 spring 容器来实例化该类以防止字段注入。
-> 在字段注入的情况下不能使用“final”关键字,这意味着你不能使字段不可变。
-> 它内部使用反射
我想知道 @Autowired 内部到底是如何工作的,它如何使用反射,我试图了解上述所有点背后的确切原因,当我们编写以下代码时幕后会发生什么:
@Component
public class B {
@Autowired
private A a1;
}
Run Code Online (Sandbox Code Playgroud)
我已经阅读过有关此主题的堆栈溢出的类似问题,但我找不到我正在寻找的确切解释。
我有一个控制器
@RestController
public class Create {
@Autowired
private ComponentThatDoesSomething something;
@RequestMapping("/greeting")
public String call() {
something.updateCounter();
return "Hello World " + something.getCounter();
}
}
Run Code Online (Sandbox Code Playgroud)
我有该控制器的组件
@Component
public class ComponentThatDoesSomething {
private int counter = 0;
public void updateCounter () {
counter++;
}
public int getCounter() {
return counter;
}
}
Run Code Online (Sandbox Code Playgroud)
我也对我的控制器进行了测试。
@RunWith(SpringRunner.class)
@SpringBootTest
public class ForumsApplicationTests {
@Test
public void contextLoads() {
Create subject = new Create();
subject.call();
subject.call();
assertEquals(subject.call(), "Hello World 2");
}
}
Run Code Online (Sandbox Code Playgroud)
当控制器调用 时,测试失败something.updateCounter()。我得到一个NullPointerException …
java ×9
spring ×5
spring-boot ×4
autowired ×3
javabeans ×2
annotations ×1
final ×1
guice ×1
junit ×1
required ×1
spring-bean ×1
spring-ldap ×1