注解替代Spring生命周期实现类
在早期的 Spring 中,我们都是使用 XML 来进行相应的 Bean 依赖描述和属性描述,但在 Spring Boot 中大多还是习惯使用注解的方式来实现,那这里我就来总结下在 Spring 生命周期中,有哪些类提供了扩展可以给我们实现,以及原先 xml 的方式和注解方式的两种实现方式。
# Spring IOC
# @Bean
<bean id="student" class="com.xinhua.study.bean.Student" scope="prototype" init-method="init()" destroy-method="destroy()"/>
# @Scope
scope="singleton/prototype"
# @PostConstruct
init-method
# @PreDestroy
destroy-method
# Spring DI
Autowired+Qualifier=Resource 这就是他们三者的关系,Autowired 根据类型找实现类,一个接口有多个实现类时需要通过 Qualifier 来指明需要哪个实现类,这是就需要 Autowired+Qualifier 一起使用才可以。Resource 则是不声明名称时按照类型查找效果与 Autowired 相同,声明名称时就等于 Autowired+Qualifier 的组合
# @Autowired
@Autowired 可以单独使用。如果单独使用,它将按类型装配。因此,如果在容器中声明了多个相同类型的 bean,则会出现问题,因为 @Autowired 不知道要使用哪个 bean 来注入。因此,使用 @Qualifier 与 @Autowired 一起,通过指定 bean 名称来阐明实际装配的 bean
ref="类型"
# @Qualifier
@Qualifier 默认按名称装配(这个注解是属于 spring 的),value 默认 @Qualifier (value = "") 空值。
ref="类型"
# @Resource
@Resource(这个注解属于 J2EE 的),默认按照名称进行装配,名称可以通过 name 属性进行指定, 如果没有指定 name 属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在 setter 方法上默认取属性名进行装配。 当找不到与名称匹配的 bean 时才按照类型进行装配。但是需要注意的是,如果 name 属性一旦指定,就只会按照名称进行装配。
ref="类型"
# @Value
给基本数据类型赋值
ref="基础数据类型"
# Spring AOP
# @Aspect
声明界面
apo:aspect
# @Before
前置通知
apo:before
# @AfterReturning
后置正常通知
aop:after-returning
# @AfterThrowing
后置异常通知
aop:after-throwing
# @After
最终通知
aop:after
# @Around
环绕通知
aop:around
# 其他注解
# @Order
最开始 Order 注解用于切面的优先级指定;在 4.0 之后对它的功能进行了增强,支持集合的注入时,指定集合中 bean 的顺序,并且特别指出了,它对于单实例的 bean 之间的顺序,没有任何影响。
注解 @Order 或者接口 Ordered 的作用是定义 Spring IOC 容器中 Bean 的执行顺序的优先级,而不是定义 Bean 的加载顺序,Bean 的加载顺序不受 @Order 或 Ordered 接口的影响;
@Order 注解不能指定 bean 的加载顺序,它适用于 AOP 的优先级,以及将多个 Bean 注入到集合时,这些 bean 在集合中的顺序
# 错误使用
// 错误使用方法 1
@Component
@Order(2)
public class OrderA {
public OrderA() {
System.out.println("************ A ************");
}
}
@Component
@Order(1)
public class OrderB {
public OrderB() {
System.out.println("************ B ************");
}
}
// 错误使用方法 2
@Configuration
public class OrderBeanConfig {
@Order(2)
@Bean
public OrderC orderC() {
return new OrderC();
}
@Order(1)
@Bean
public OrderD orderD() {
return new OrderD();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 正确使用
@Component
@Order(value = 3)
public class AnoBeanA implements IBean{
public AnoBeanA() {
System.out.println("************ AnoBean A ************");
}
}
@Component
@Order(value = 2)
public class AnoBeanB implements IBean{
public AnoBeanB() {
System.out.println("************ AnoBean B ************");
}
}
@Component
public class AnoBean {
public AnoBean(List<IBean> anoBeanList) {
for (IBean bean : anoBeanList) {
System.out.println("in ano testBean: "+ bean.getClass())
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# @AutoConfigureOrder
@AutoConfigureOrder 指定外部依赖的 AutoConfig 的加载顺序(即定义在 / META-INF/spring.factories 文件中的配置 bean 优先级),在当前工程中使用这个注解并没有什么用,同样的 @AutoConfigureBefore 和 @AutoConfigureAfter 这两个注解的适用范围和 @AutoConfigureOrder 一样
# @EventListener
@EventListener 注解用于监听容器中发布的事件,当容器中发布事件时,@EventListener 注解的方法会收到通知,并执行。
// Custom Event Class
public class UserRegisteredEvent {
private final String username;
public UserRegisteredEvent(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
}
// Event Publisher
@Component
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void registerUser(String username) {
// Perform registration logic here...
System.out.println("User registered: " + username);
// Publish event
eventPublisher.publishEvent(new UserRegisteredEvent(username));
}
}
// Event Listener
@Component
public class WelcomeEmailService {
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
System.out.println("Sending welcome email to: " + event.getUsername());
}
}
// Event Listener with Conditional Handling
@Component
public class AdminNotificationService {
@EventListener(condition = "#event.username == 'admin'")
public void notifyAdmin(UserRegisteredEvent event) {
System.out.println("Special handling for admin user: " + event.getUsername());
}
}
// Controller to trigger the event
@RestController
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/register")
public String registerUser(@RequestBody String username) {
userService.registerUser(username);
return "User Registered!";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
更复杂的条件示例:
@EventListener(condition = "#event.user=='arvind'") // Equality
@EventListener(condition = "#event.user!='arvind'") // Inequality
@EventListener(condition = "#event.age > 18") // Greater than
@EventListener(condition = "#event.age >= 18") // Greater than or equal
@EventListener(condition = "#event.age < 18") // Less than
@EventListener(condition = "#event.age <= 18") // Less than or equal
@EventListener(condition = "#event.user matches 'ar.*'") // Regex match
@EventListener(condition = "#event.role.equals('ADMIN')") // Object equality
// Logical operators
@EventListener(condition = "#event.age > 18 and #event.user=='arvind'") // AND
@EventListener(condition = "#event.age > 18 or #event.user=='arvind'") // OR
@EventListener(condition = "!#event.isDeleted") // NOT
// Collection operations
@EventListener(condition = "#event.roles.contains('ADMIN')") // Contains
@EventListener(condition = "#event.tags.size() > 0") // Size check
// Null checks
@EventListener(condition = "#event.user != null") // Not null
@EventListener(condition = "#event.user?.length() > 5") // Safe navigation
@EventListener(condition = "#event instanceof T(com.example.AdminEvent)") // Type check
@EventListener(condition = "#event.timestamp > T(java.time.Instant).now().minusSeconds(3600)") // Time comparison
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20