Spring 的这些基础注解仅仅是简化了 XML 的配置,但是并不能替代 XML。Spring 使用注解后是如何进行解耦的呢(注解都写死在代理里)?其实 Spring 在应用注解开发的时候,如果对注解不满意,还是可以通过 Spring 的配置文件(XML)进行覆盖的。
想要应用 Spring 注解进行开发,还需要进行如下配置,告知 Spring 扫描对应包下的注解。
<!-- 配置扫描包 --> <context:component-scan base-package="world.xuewei"/>
对象创建相关
@Component
替换原来的 标签,将一个类声明为组件,通常是指那些没有明显角色的类。
@Component public class Account implements Serializable {
就相当于如下的 XML 配置:
<bean id="account" class="world.xuewei.entity.Account"/>
@Component 注解提供了默认的 id 属性,使用类名的首单词首字母小写的方式,即 Account -> account
、UserService -> userService
。原来 bean 标签的 class 属性,就可以通过反射的方式获取类的全限定类名。
@Component 也可以手动指定 id 属性,如下:
@Component("acc") public class Account implements Serializable {
如果想要在 XML 中覆盖注解配置,可以在配置文件中配置 bean,要求 bean 的 id 和 class 都需要和注解的配置一致,进而可以在 bean 标签的进行注入配置等。
<bean id="acc" class="world.xuewei.entity.Account"> <property name="id" value="1"/> </bean>
@Component 的衍生注解
@Repository
:将 DAO 类声明为 Spring Bean,用于数据库访问层。@Service
:将 Service 类声明为 Spring Bean,用于业务逻辑层。@Controller
:将 Controller 类声明为 Spring Bean,用于 MVC 控制器层。
这些衍生注解的用法细节和 @Component 是一模一样的。只不过是换了个更有针对性的名字。
注意:Spring 整合 Mybatis 开发过程中,不使用 @Component 和 @Repository。
@Scope
@Scope
注解用于指定 Spring 管理的 Bean 的作用域(Scope),即控制 Bean 的生命周期和实例化方式。通过 @Scope
注解,你可以将一个类或方法标记为一个 Spring Bean ,并指定其作用域。
在 Spring 中,常用的作用域包括以下几种:
- singleton(默认):每个 Spring 容器中只存在一个 Bean 实例。无论有多少次请求,都返回同一个 Bean 实例。
- prototype:每次请求都会创建一个新的 Bean 实例。每次使用
getBean()
方法获取该 Bean 时,都会得到一个全新的实例。 - request:每个 HTTP 请求都会创建一个新的 Bean 实例。当请求结束后,Bean 实例将被销毁。
- session:每个 HTTP 会话(Session)都会创建一个新的 Bean 实例。当会话结束后,Bean 实例将被销毁。
@Component @Scope("prototype") public class MyBean { // ... }
注意:如果不添加 @Scope 注解,那么默认这个 Bean 就是单例的 Singleton。
@Lazy
@Lazy
是 Spring 框架中的一个注解,用于延迟加载(Lazy Loading)Bean 实例。当一个 Bean 被标记为 @Lazy
时,它将在第一次使用时才会被初始化,而不是在应用启动时就创建。
使用 @Lazy
注解可以提高应用的性能和资源利用率,特别是在存在大量复杂或耗时的 Bean 初始化过程时。通过延迟加载,可以避免在启动阶段创建所有的 Bean 实例,从而加快应用的启动速度。
例如,假设有一个名为 MyBean
的类,我们可以将其标记为 @Lazy
:
@Component @Lazy public class MyBean { // ... }
在这种情况下,当 Spring 上下文初始化时,不会立即创建 MyBean
的实例。而是在第一次访问该 Bean 时才进行初始化。
注意:@Lazy 注解只针对单实例(
@Scope("singleton")
) Bean 生效。当 @Scope 不为 singleton 时,指定 @Lazy 无意义。
生命周期相关
以下的两个注解并不是 Spring 提供的,而是 JSR(JavaEE 规范)520 提供,Spring 做了很好的兼容。
@PostConstruct
当一个 Bean 被标记了 @PostConstruct
注解时,在该 Bean 的依赖注入完成后,容器会自动调用被注解的方法。这个方法可以用来执行一些初始化操作,例如初始化成员变量、建立连接、加载数据等。
使用 @PostConstruct
注解的方法需要满足以下条件:
- 方法不能有任何参数。
- 方法的返回类型必须为
void
。 - 方法不能抛出受检查的异常。
例如,假设有一个名为 MyBean
的类,我们可以在其中定义一个使用 @PostConstruct
注解的方法:
@Component public class MyBean { @PostConstruct public void init() { // 初始化操作 } }
需要注意的是,
@PostConstruct
注解通常与依赖注入(如@Autowired
)一起使用,以确保依赖关系已经注入完成后再执行初始化操作。
@PreDestroy
当一个 Bean 被标记了 @PreDestroy
注解时,在该 Bean 被销毁之前,容器会自动调用被注解的方法。这个方法可以用来执行一些清理操作,例如释放资源、关闭连接等。
使用 @PreDestroy
注解的方法需要满足以下条件:
- 方法不能有任何参数。
- 方法的返回类型必须为
void
。 - 方法不能抛出受检查的异常。
例如,假设有一个名为 MyBean
的类,我们可以在其中定义一个使用 @PreDestroy
注解的方法:
@Component public class MyBean { @PreDestroy public void cleanup() { // 清理操作 } }
需要注意的是,
@PreDestroy
注解通常与依赖注入(如@Autowired
)一起使用,以确保依赖关系已经注入完成后再执行清理操作。
注入相关
@Autowired
@Autowired
注解是 Spring 框架中用于实现依赖注入的注解之一。通过 @Autowired
注解,你可以自动将依赖的 Bean 注入到需要使用它的地方,无需手动创建和管理依赖对象。
使用 @Autowired
注解时,Spring 会根据类型进行自动装配。具体来说,当 Spring 容器中存在多个与被注入字段或方法参数类型匹配的 Bean 时,Spring 会根据一定的规则选择合适的 Bean 进行注入。如果只有一个匹配的 Bean,Spring 会直接将其注入;如果没有匹配的 Bean,将会抛出异常。
@Autowired
注解可以应用在以下位置:
- 字段上(直接放在成员变量上的时候,Spring 通过反射为变成进行赋值注入,不是通过 Set 方法):
@Autowired private MyDependency myDependency;
- 构造函数上:
@Autowired public MyClass(MyDependency myDependency) { this.myDependency = myDependency; }
- Set 方法上(通过调用 Set 方法进行赋值注入):
@Autowired public void setMyDependency(MyDependency myDependency) { this.myDependency = myDependency; }
将下面的 Spring XML 配置可以转换为:
<bean id="accountService" class="world.xuewei.service.AccountServiceImpl"> <property name="accountDao" ref="accountDao"/> </bean>
@Repository public class AccountDao { void insert(Account account){ // ... } }
@Service public class AccountService { private AccountDao accountDao; public AccountDao getAccountDao() { return accountDao; } @Autowired public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } void register(Account account) { accountDao.insert(account); } }
@Autowired 是基于类型进行注入的,要注入的 Bean 需要是定义成员变量的相同类型、或子类、或实现类。
@Qualifier
@Qualifier
注解是 Spring 框架中用于解决依赖注入歧义性的注解。当存在多个类型相同的 Bean 时,使用 @Qualifier
注解可以指定要注入的特定 Bean。
在使用 @Autowired
进行自动装配时,如果存在多个与被注入字段或方法参数类型匹配的 Bean,Spring 无法确定要注入哪个 Bean,从而抛出异常。这时,可以结合 @Qualifier
注解来解决歧义性问题。
@Qualifier
注解可以应用在以下位置:
- 字段上:
@Autowired @Qualifier("myBean") private MyInterface myBean;
- 构造函数上:
@Autowired public MyClass(@Qualifier("myBean") MyInterface myBean) { this.myBean = myBean; }
- Set 方法上:
@Autowired public void setMyBean(@Qualifier("myBean") MyInterface myBean) { this.myBean = myBean; }
需要注意的是,
@Qualifier
注解配合@Autowired
注解使用时,要确保指定的 Bean 名称与容器中的 Bean 名称一致。通常情况下,Bean名称是通过@Component
、@Service
、@Repository
等注解指定的,或者是根据默认的命名规则生成的。
@Resouce
@Resource
注解是 Java EE(JSR 250) 标准中用于实现依赖注入的注解之一。它可以用于注入其他组件或资源,如数据源、JMS 队列等。在 Spring 框架中,@Resource
注解也可以用于实现依赖注入。
与 @Autowired
注解不同的是,@Resource
注解既可以按照名称进行注入,也可以按照类型进行注入。当使用 @Resource
注解按照名称进行注入时,它会根据指定的名称在容器中查找对应的 Bean 进行注入;当使用 @Resource
注解按照类型进行注入时,它会根据指定的类型在容器中查找对应的 Bean 进行注入。
- 使用名称注入:@Resource(name = “XXX”),此时相当于 @Autowired 和 @Qualifier 的组合,但是需要注意的是,@Resource(name = “XXX”) 如果没有匹配到指定名称的 Bean,那么会按照类型再去匹配。
- 使用类型注入:单独使用 @Resource,此时相当于 @Autowired。
@Resource
注解可以应用在以下位置:
- 字段上:
@Resource(name = "myBean") private MyInterface myBean;
- 构造函数上:
@Autowired public MyClass(@Resource(name = "myBean") MyInterface myBean) { this.myBean = myBean; }
- Set 方法上:
@Resource(name = "myBean") public void setMyBean(MyInterface myBean) { this.myBean = myBean; }
需要注意的是,
@Resource
注解在按照名称进行注入时,要确保指定的 Bean 名称与容器中的 Bean 名称一致。通常情况下,Bean名称是通过@Component
、@Service
、@Repository
等注解指定的,或者是根据默认的命名规则生成的。
@Inject
@Inject
是 Java 中的一个注解,用于进行依赖注入。它是 Java 的标准依赖注入规范(JSR 330)中定义的注解之一。
使用 @Inject
注解可以在需要依赖的地方进行注入,例如字段、构造方法、普通方法等。它可以与其他依赖注入框架(如 Spring、CDI)一起使用,也可以作为 Java 自带的依赖注入机制的一部分使用。
@Inject 的用法与 @Autowired 完全一致。都是基于类型的注入。但是我们想要使用 Inject 注解,我们还需要额外引入依赖。
<dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
@Value
@Value
注解是 Spring 框架中用于注入值的注解。它可以用于将配置文件中的值或者直接指定的值注入(通过 ${}
符号读取)到 Bean 中的字段、方法参数或构造函数中。
定义配置文件 test.properties
内容如下:
my.property=XW
配置 Spring 加载指定配置文件:
<!-- 指定加载配置文件 --> <context:property-placeholder location="classpath:test.properties"/>
@Value
注解可以应用在以下位置:
- 字段上:
@Value("${my.property}")
- 构造函数上:
@Autowired public MyClass(@Value("${my.property}") String myProperty) { this.myProperty = myProperty; }
- Set 方法上:
@Autowired public void setMyProperty(@Value("${my.property}") String myProperty) { this.myProperty = myProperty; }
注意:@Value 注解不能标记在静态属性中。如果是静态的变量,那么无法进行复制(但是不会报错)。
注意:@Value 注解 + properties 这种方式不能注入集合类型的数据。可以通过 @Value + YAML 文件的方式实现集合类型的数据的注入。
@PropertySource
在上面的 @Value 笔记中,我们需要在 Spring 的配置文件中配置加载指定的配置文件。Spring 提供了 @PropertySource 注解让我们省去配置 XML。
@Component @PropertySource("classpath:test.properties") public class Account implements Serializable { private Integer id; @Value("${my.property}") private String name; // .. }