面试题:Spring 一共有几种注入方式?

Spring 提供了多种依赖注入(Dependency Injection, DI)的方式,用于将依赖对象注入到目标对象中。以下是 Spring 中常见的几种注入方式:


1. 基于构造函数的注入(Constructor Injection)

通过构造函数将依赖注入到目标对象中。Spring 容器会调用目标类的构造函数,并传入所需的依赖。

优点:

  • 保证依赖不可变(final 字段)。
  • 适合强制依赖的场景。
  • 便于单元测试。

示例:

public class UserService {
private final UserRepository userRepository;
@Autowired // 可省略
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
public class UserService {
    private final UserRepository userRepository;

    @Autowired // 可省略
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}
public class UserService { private final UserRepository userRepository; @Autowired // 可省略 public UserService(UserRepository userRepository) { this.userRepository = userRepository; } }

配置:

<bean id="userRepository" class="com.example.UserRepository" />
<bean id="userService" class="com.example.UserService">
<constructor-arg ref="userRepository" />
</bean>
<bean id="userRepository" class="com.example.UserRepository" />
<bean id="userService" class="com.example.UserService">
    <constructor-arg ref="userRepository" />
</bean>
<bean id="userRepository" class="com.example.UserRepository" /> <bean id="userService" class="com.example.UserService"> <constructor-arg ref="userRepository" /> </bean>

2. 基于 Setter 方法的注入(Setter Injection)

通过 Setter 方法将依赖注入到目标对象中。Spring 容器会调用目标类的 Setter 方法,并传入所需的依赖。

优点:

  • 灵活性高,适合可选依赖。
  • 符合 JavaBean 规范。

示例:

public class UserService {
private UserRepository userRepository;
@Autowired // 可省略
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
public class UserService {
    private UserRepository userRepository;

    @Autowired // 可省略
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}
public class UserService { private UserRepository userRepository; @Autowired // 可省略 public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } }

配置:

<bean id="userRepository" class="com.example.UserRepository" />
<bean id="userService" class="com.example.UserService">
<property name="userRepository" ref="userRepository" />
</bean>
<bean id="userRepository" class="com.example.UserRepository" />
<bean id="userService" class="com.example.UserService">
    <property name="userRepository" ref="userRepository" />
</bean>
<bean id="userRepository" class="com.example.UserRepository" /> <bean id="userService" class="com.example.UserService"> <property name="userRepository" ref="userRepository" /> </bean>

3. 基于字段的注入(Field Injection)

通过反射直接将依赖注入到目标对象的字段中。Spring 容器会直接访问目标类的字段,并设置所需的依赖。

优点:

  • 代码简洁,无需编写构造函数或 Setter 方法。

缺点:

  • 不利于单元测试(需要通过反射注入依赖)。
  • 隐藏了依赖关系,不够直观。

示例:

public class UserService {
@Autowired
private UserRepository userRepository;
}
public class UserService {
    @Autowired
    private UserRepository userRepository;
}
public class UserService { @Autowired private UserRepository userRepository; }

配置:

无需额外配置,Spring 会自动注入。


4. 基于方法的注入(Method Injection)

通过任意方法将依赖注入到目标对象中。Spring 容器会调用目标类的指定方法,并传入所需的依赖。

优点:

  • 灵活性高,适合复杂场景。

示例:

public class UserService {
private UserRepository userRepository;
@Autowired
public void injectUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
public class UserService {
    private UserRepository userRepository;

    @Autowired
    public void injectUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}
public class UserService { private UserRepository userRepository; @Autowired public void injectUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } }

配置:

无需额外配置,Spring 会自动注入。


5. 基于接口的注入(Interface Injection)

通过实现特定接口将依赖注入到目标对象中。Spring 容器会调用接口方法,并传入所需的依赖。

示例:

public interface UserRepositoryAware {
void setUserRepository(UserRepository userRepository);
}
public class UserService implements UserRepositoryAware {
private UserRepository userRepository;
@Override
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
public interface UserRepositoryAware {
    void setUserRepository(UserRepository userRepository);
}

public class UserService implements UserRepositoryAware {
    private UserRepository userRepository;

    @Override
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}
public interface UserRepositoryAware { void setUserRepository(UserRepository userRepository); } public class UserService implements UserRepositoryAware { private UserRepository userRepository; @Override public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } }

配置:

<bean id="userRepository" class="com.example.UserRepository" />
<bean id="userService" class="com.example.UserService">
<property name="userRepository" ref="userRepository" />
</bean>
<bean id="userRepository" class="com.example.UserRepository" />
<bean id="userService" class="com.example.UserService">
    <property name="userRepository" ref="userRepository" />
</bean>
<bean id="userRepository" class="com.example.UserRepository" /> <bean id="userService" class="com.example.UserService"> <property name="userRepository" ref="userRepository" /> </bean>

6. 基于注解的注入(Annotation-based Injection)

通过注解将依赖注入到目标对象中。Spring 支持多种注解,如 @Autowired@Resource@Inject 等。

(1)@Autowired

  • 默认按类型注入,如果存在多个同类型的 Bean,可以结合 @Qualifier 指定名称。

示例:

public class UserService {
@Autowired
@Qualifier("userRepository")
private UserRepository userRepository;
}
public class UserService {
    @Autowired
    @Qualifier("userRepository")
    private UserRepository userRepository;
}
public class UserService { @Autowired @Qualifier("userRepository") private UserRepository userRepository; }

(2)@Resource

  • 默认按名称注入,如果未指定名称,则按类型注入。

示例:

public class UserService {
@Resource(name = "userRepository")
private UserRepository userRepository;
}
public class UserService {
    @Resource(name = "userRepository")
    private UserRepository userRepository;
}
public class UserService { @Resource(name = "userRepository") private UserRepository userRepository; }

(3)@Inject

  • @Autowired 类似,但需要引入 javax.inject 依赖。

示例:

import javax.inject.Inject;
public class UserService {
@Inject
private UserRepository userRepository;
}
import javax.inject.Inject;

public class UserService {
    @Inject
    private UserRepository userRepository;
}
import javax.inject.Inject; public class UserService { @Inject private UserRepository userRepository; }

7. 基于 Java 配置的注入(Java-based Configuration)

通过 Java 配置类将依赖注入到目标对象中。Spring 容器会调用配置类中的方法,并返回所需的依赖。

示例:

@Configuration
public class AppConfig {
@Bean
public UserRepository userRepository() {
return new UserRepository();
}
@Bean
public UserService userService() {
return new UserService(userRepository());
}
}
@Configuration
public class AppConfig {
    @Bean
    public UserRepository userRepository() {
        return new UserRepository();
    }

    @Bean
    public UserService userService() {
        return new UserService(userRepository());
    }
}
@Configuration public class AppConfig { @Bean public UserRepository userRepository() { return new UserRepository(); } @Bean public UserService userService() { return new UserService(userRepository()); } }

8. 基于 XML 配置的注入(XML-based Configuration)

通过 XML 配置文件将依赖注入到目标对象中。Spring 容器会解析 XML 文件,并注入所需的依赖。

示例:

<bean id="userRepository" class="com.example.UserRepository" />
<bean id="userService" class="com.example.UserService">
<property name="userRepository" ref="userRepository" />
</bean>
<bean id="userRepository" class="com.example.UserRepository" />
<bean id="userService" class="com.example.UserService">
    <property name="userRepository" ref="userRepository" />
</bean>
<bean id="userRepository" class="com.example.UserRepository" /> <bean id="userService" class="com.example.UserService"> <property name="userRepository" ref="userRepository" /> </bean>

总结

Spring 提供了多种依赖注入方式,常见的有:

  1. 构造函数注入:适合强制依赖。
  2. Setter 方法注入:适合可选依赖。
  3. 字段注入:代码简洁,但不利于测试。
  4. 方法注入:灵活性高。
  5. 接口注入:通过接口方法注入。
  6. 注解注入:如 @Autowired@Resource@Inject
  7. Java 配置注入:通过 Java 配置类注入。
  8. XML 配置注入:通过 XML 配置文件注入。

根据具体需求选择合适的注入方式,可以提高代码的可维护性和灵活性。

THE END
点赞10 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容