Spring 框架中 Setter 注入与构造函数注入的实现
Setter 注入(Setter Injection)
Setter 注入是通过类的公共 Setter 方法来实现依赖关系的配置。这种方式允许在对象实例化后灵活地更改依赖关系。
XML 配置文件 (app-config.xml)
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 使用 p 命名空间简化 Setter 注入 -->
<bean id="displayer"
class="com.example.spring.xml.ConsoleDataDisplayer"
p:dataSource-ref="source"/>
<bean id="source"
class="com.example.spring.xml.DefaultContentSource"/>
</beans>
Java 接口定义
package com.example.spring;
public interface ContentSource {
String provideContent();
}
public interface DataDisplayer {
void display();
void setDataSource(ContentSource source);
ContentSource getDataSource();
}
Java 类实现
package com.example.spring.xml;
import com.example.spring.ContentSource;
public class DefaultContentSource implements ContentSource {
@Override
public String provideContent() {
return "Hello, Spring Setter Injection!";
}
}
package com.example.spring.xml;
import com.example.spring.ContentSource;
import com.example.spring.DataDisplayer;
public class ConsoleDataDisplayer implements DataDisplayer {
private ContentSource dataSource;
@Override
public void display() {
if (dataSource == null) {
throw new IllegalStateException("The dataSource property must be initialized.");
}
System.out.println(dataSource.provideContent());
}
@Override
public void setDataSource(ContentSource source) {
this.dataSource = source;
}
@Override
public ContentSource getDataSource() {
return this.dataSource;
}
}
启动程序
package com.example.spring;
import org.springframework.context.support.GenericXmlApplicationContext;
public class SpringRunner {
public static void main(String[] args) {
GenericXmlApplicationContext context = new GenericXmlApplicationContext();
context.load("classpath:app-config.xml");
context.refresh();
DataDisplayer displayer = context.getBean("displayer", DataDisplayer.class);
displayer.display();
context.close();
}
}
构造函数注入(Constructor Injection)
构造函数注入确保了 Bean 在创建时就处于完整状态。Spring 支持通过参数索引、类型或名称来解决构造函数歧义。
XML 配置文件 (constructor-config.xml)
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 使用 c 命名空间进行构造函数注入 -->
<bean id="customSource"
class="com.example.spring.xml.ConfigurableContentSource"
c:text="Dynamic message via constructor"/>
<!-- 演示类型匹配解决构造函数重载歧义 -->
<bean id="typeDemo"
class="com.example.spring.xml.ConstructorTypeResolver">
<constructor-arg type="int" value="1024"/>
</bean>
</beans>
Java 类实现
package com.example.spring.xml;
import com.example.spring.ContentSource;
public class ConfigurableContentSource implements ContentSource {
private final String text;
public ConfigurableContentSource(String text) {
this.text = text;
}
@Override
public String provideContent() {
return text;
}
}
package com.example.spring.xml;
import org.springframework.context.support.GenericXmlApplicationContext;
public class ConstructorTypeResolver {
private String val;
public ConstructorTypeResolver(String val) {
System.out.println("String constructor triggered");
this.val = val;
}
public ConstructorTypeResolver(int val) {
System.out.println("Integer constructor triggered");
this.val = "Value: " + val;
}
@Override
public String toString() {
return val;
}
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:constructor-config.xml");
ctx.refresh();
ConstructorTypeResolver resolver = ctx.getBean("typeDemo", ConstructorTypeResolver.class);
System.out.println("Result: " + resolver);
ContentSource source = ctx.getBean("customSource", ContentSource.class);
System.out.println("Source output: " + source.provideContent());
ctx.close();
}
}