控制反转(IoC)和依赖注入(DI)实现及常用注解
在Spring框架里,控制反转(IoC)和依赖注入(DI)是核心特性,以下将介绍实现它们的各种方式以及常用注解。
配置文件方式
详细版:
Spring IoC与DI详解:从Bean概念到手写实现
XML 配置
XML 配置是 Spring 早期实现 IoC 和 DI 的主要方式,通过 <bean>
标签定义 Bean,使用不同的属性和子标签来完成依赖注入。
1. Bean 定义与基本属性
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 定义一个 Bean,id 是唯一标识,class 是该 Bean 对应的类 --><bean id="userService" class="com.example.service.UserService"><!-- 可以通过 init-method 和 destroy-method 指定 Bean 的初始化和销毁方法 --><property name="initMethod" value="init"/><property name="destroyMethod" value="destroy"/></bean>
</beans>
在上述示例中,id
是 Bean 在 Spring 容器中的唯一标识,class
指定了该 Bean 对应的 Java 类。init-method
和 destroy-method
可以让开发者在 Bean 初始化和销毁时执行特定的方法。
2. 构造函数注入
<bean id="userService" class="com.example.service.UserService"><!-- 通过 constructor-arg 标签进行构造函数注入 --><constructor-arg ref="userDao"/>
</bean>
<bean id="userDao" class="com.example.dao.UserDaoImpl"/>
constructor-arg
标签用于向构造函数传递参数,ref
属性表示引用另一个 Bean。这里 UserService
的构造函数接收一个 UserDao
类型的参数,通过 ref
引用了 userDao
这个 Bean。
3. Setter 方法注入
<bean id="userService" class="com.example.service.UserService"><!-- 通过 property 标签进行 Setter 方法注入 --><property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="com.example.dao.UserDaoImpl"/>
property
标签用于调用 Setter 方法注入依赖,name
属性指定要注入的属性名,ref
引用另一个 Bean。
4. 自动装配
<bean id="userService" class="com.example.service.UserService" autowire="byType"/>
<bean id="userDao" class="com.example.dao.UserDaoImpl"/>
autowire
属性可以指定自动装配模式,常见的有 byName
(按属性名匹配)、byType
(按类型匹配)等。上述示例中,userService
会根据 byType
模式自动注入 UserDao
类型的 Bean。
注解方式
先列出表格:
类别 | 注解 | 作用 | 使用示例 | 注意事项 |
---|---|---|---|---|
组件定义注解 | @Component | 通用注解,将类标记为Spring组件,Spring自动扫描并纳入容器管理 | java<br>@Component<br>public class GeneralComponent {<br> // 类的具体实现<br>}<br> | 无 |
@Service | @Component 的特化注解,标记业务逻辑层类 | java<br>@Service<br>public class UserService {<br> public void handleBusiness() {<br> // 业务逻辑处理<br> }<br>}<br> | 无 | |
@Repository | @Component 的特化注解,标记数据访问层类,还可进行数据访问异常转换 | java<br>@Repository<br>public class UserDaoImpl implements UserDao {<br> public User findById(Long id) {<br> // 根据ID查找用户的逻辑<br> return null;<br> }<br>}<br> | 无 | |
@Controller | @Component 的特化注解,标记Spring MVC控制器类,处理HTTP请求 | java<br>@Controller<br>@RequestMapping("/user")<br>public class UserController {<br> @GetMapping("/info")<br> @ResponseBody<br> public String getUserInfo() {<br> return "User Info";<br> }<br>}<br> | 需结合Spring MVC相关注解使用 | |
依赖注入注解 | @Autowired | Spring提供的自动装配注解,默认按类型装配,可用于字段、构造函数、Setter方法 | java<br>@Component<br>public class UserController {<br> @Autowired<br> private UserService userService;<br>}<br> | 存在多个相同类型Bean时会有歧义,需结合@Qualifier 使用 |
@Qualifier | 与@Autowired 配合,当存在多个相同类型Bean时,指定要注入的Bean名称 | java<br>@Component<br>public class UserController {<br> @Autowired<br> @Qualifier("specificUserService")<br> private UserService userService;<br>}<br> | @Qualifier 中的名称要与目标Bean的名称一致 | |
@Resource | JSR - 250规范注解,默认按名称注入,未指定名称则按类型注入 | java<br>@Component<br>public class UserController {<br> @Resource(name = "userService")<br> private UserService userService;<br>}<br> | 无 | |
@Inject | JSR - 330规范注解,功能类似@Autowired | java<br>import javax.inject.Inject;<br>@Component<br>public class UserController {<br> @Inject<br> private UserService userService;<br>}<br> | 需要引入JSR - 330相关依赖 | |
配置类注解 | @Configuration | 标记Java配置类,类中可用@Bean 定义Bean | java<br>@Configuration<br>public class AppConfig {<br> @Bean<br> public UserService userService() {<br> return new UserService();<br> }<br>}<br> | 无 |
@Bean | 在@Configuration 类的方法上使用,方法返回值作为Bean注册到容器 | java<br>@Configuration<br>public class AppConfig {<br> @Bean<br> public UserDao userDao() {<br> return new UserDaoImpl();<br> }<br>}<br> | 方法名可作为Bean的默认名称,可在方法中进行复杂初始化操作 |
组件定义注解
这些注解用于将类标记为 Spring 组件,让 Spring 容器自动扫描并管理这些类。
1. @Component
import org.springframework.stereotype.Component;@Component
public class UserService {// 类的具体实现public void doSomething() {System.out.println("UserService is doing something.");}
}
@Component
是一个通用的组件注解,被标记的类会被 Spring 容器识别并创建为 Bean。
2. @Service
import org.springframework.stereotype.Service;@Service
public class UserService {// 业务逻辑实现public void saveUser() {// 保存用户的业务逻辑}
}
@Service
是 @Component
的特化注解,通常用于标记业务逻辑层的类,语义更加明确,方便代码的阅读和维护。
3. @Repository
import org.springframework.stereotype.Repository;@Repository
public class UserDaoImpl implements UserDao {// 数据访问实现public User findUserById(Long id) {// 根据 ID 查询用户的逻辑return null;}
}
@Repository
同样是 @Component
的特化注解,主要用于标注数据访问层的类。Spring 还会对标注了 @Repository
的类进行数据访问异常的转换,方便统一处理异常。
4. @Controller
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
@RequestMapping("/user")
public class UserController {// 处理请求的方法@GetMapping("/hello")@ResponseBodypublic String sayHello() {return "Hello, User!";}
}
@Controller
是 @Component
的特化注解,用于标记 Spring MVC 的控制器类,负责处理 HTTP 请求。
依赖注入注解
这些注解用于实现依赖的自动注入,减少手动配置的工作量。
1. @Autowired
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class UserController {// 字段注入@Autowiredprivate UserService userService;// 构造函数注入private UserDao userDao;@Autowiredpublic UserController(UserDao userDao) {this.userDao = userDao;}// Setter 方法注入private AnotherService anotherService;@Autowiredpublic void setAnotherService(AnotherService anotherService) {this.anotherService = anotherService;}
}
@Autowired
可以用于字段、构造函数和 Setter 方法,默认按类型进行自动装配。如果存在多个相同类型的 Bean,可能会出现注入歧义,需要结合 @Qualifier
注解使用。
2. @Qualifier
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;@Component
public class UserController {@Autowired@Qualifier("specificUserService")private UserService userService;// 其他代码
}
当存在多个相同类型的 Bean 时,@Qualifier
用于指定要注入的 Bean 的名称,解决注入歧义问题。
3. @Resource
import javax.annotation.Resource;
import org.springframework.stereotype.Component;@Component
public class UserController {// 按名称注入@Resource(name = "userService")private UserService userService;// 按类型注入@Resourceprivate UserDao userDao;
}
@Resource
是 JSR - 250 规范中的注解,默认按名称注入,如果未指定名称,则按类型注入。
4. @Inject
import javax.inject.Inject;
import org.springframework.stereotype.Component;@Component
public class UserController {@Injectprivate UserService userService;// 其他代码
}
@Inject
是 JSR - 330 规范中的注解,功能和 @Autowired
类似,用于依赖注入。
配置类注解
这些注解用于通过 Java 代码定义 Bean 和配置 Spring 容器。
1. @Configuration
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic UserService userService() {return new UserService();}@Beanpublic UserDao userDao() {return new UserDaoImpl();}
}
@Configuration
用于标记一个类为 Java 配置类,该类中的方法可以使用 @Bean
注解定义 Bean。
2. @Bean
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic UserService userService() {// 可以在这里进行复杂的初始化操作UserService userService = new UserService();userService.setUserDao(userDao());return userService;}@Beanpublic UserDao userDao() {return new UserDaoImpl();}
}
@Bean
注解用于在 @Configuration
类的方法上,方法的返回值会被注册到 Spring 容器中作为一个 Bean。开发者可以在方法中进行复杂的初始化操作。
通过以上这些配置文件和注解方式,Spring 框架提供了丰富多样的手段来实现控制反转和依赖注入,开发者可以根据项目的实际情况灵活选择和组合使用。