Spring框架中常用的技巧及扩展点

Spring是现在非常流行的轻量级Java开发框架,简化Java开发,提供了丰富的功能,工作中基本都会使用到它,如框架整合;总结下Spring中常用的使用技巧及扩展点。

1、ApplicationContextAware、EnvironmentAware

ApplicationContextAware接口定义如下:

1
2
3
4
5
public interface ApplicationContextAware extends Aware {

void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

当一个类实现了ApplicationContextAware接口之后,这个类就可以方便获得ApplicationContext中的所有bean;
我们可以新建工具类,实现该接口,方便获取Spring容器中的bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component
public class ApplicationContextUtils implements ApplicationContextAware {

private static ApplicationContext context;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}

public static ApplicationContext getApplicationContext() {
return context;
}

public static Object getBean(String beanName) {
if(context != null) {
return context.getBean(beanName);
}
return null;
}

}

EnvironmentAware接口定义如下:

1
2
3
4
public interface EnvironmentAware extends Aware {

void setEnvironment(Environment environment);
}

实现了EnvironmentAware接口重写setEnvironment方法后,在项目启动时可以获得application.properties的配置文件的属性值。
我们可以写一个获取属性的工具类,这里我们使用EnvironmentAware的实现类PropertySourcesPlaceholderConfigurer,工具类继承PropertySourcesPlaceholderConfigurer;
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Component
public class EnvUtils extends PropertySourcesPlaceholderConfigurer {

private static ConfigurableEnvironment ENV;

@Override
public void setEnvironment(Environment environment) {
super.setEnvironment(environment);
if (environment instanceof ConfigurableEnvironment) {
ENV = (ConfigurableEnvironment) environment;
} else {
ENV = new StandardEnvironment();
}
}

public static String getProperty(String key) {
return ENV.getProperty(key);
}

}

2、BeanPostProcessor

bean后置处理器,接口定义如下:

1
2
3
4
5
6
7
8
9
10
11
public interface BeanPostProcessor {

default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

}

一个BeanPostProcessor可以在任意一个Bean的初始化之前以及初始化之后去额外的做一些用户自定义的逻辑,
当然,我们可以通过判断beanName来进行针对性处理(针对某个Bean,或某部分 Bean),
可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class RiverBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(Objects.equals(beanName, "userService")) {
System.out.println("userService初始化前");
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(Objects.equals(beanName, "userService")) {
System.out.println("userService初始化后");
}
return bean;
}
}

Spring中的AOP就是基于初始化后实现的,初始化后返回的对象才是最终的Bean对象。

3、InitializingBean、DisposableBean

InitializingBean接口定义如下:

1
2
3
4
5
public interface InitializingBean {

void afterPropertiesSet() throws Exception;

}

DisposableBean接口定义如下:

1
2
3
4
public interface DisposableBean {

void destroy() throws Exception;
}

如果Bean对象实现了InitializingBean接口,就调用其afterPropertiesSet()方法,初始化bean中的参数,或者校验参数;
InitializingBean执行在BeanPostProcessor的两个方法之间,顺序为:postProcessBeforeInitialization -> initializingBean -> postProcessAfterInitialization

如果Bean对象实现了DisposableBean接口,当容器关闭时回调destroy方式执行销毁逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class UserBean implements InitializingBean, DisposableBean {

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行初始化逻辑");
}

@Override
public void destroy() throws Exception {
System.out.println("执行销毁逻辑");
}
}

4、@PostConstruct、@PreDestroy

@PostConstruct在bean创建完成并且属性赋值完成,来执行初始化方法
@PreDestroy在关闭容器时调用;

1
2
3
4
5
6
7
8
9
10
11
12
13
@Service
public class AService {

@PostConstruct
public void init() {
System.out.println("执行初始化逻辑");
}

@PreDestroy
public void d() {
System.out.println("容器关闭时逻辑");
}
}

5、BeanFactoryPostProcessor

bean工厂后置处理器,该接口定义如下:

1
2
3
4
5
public interface BeanFactoryPostProcessor {

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,
BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程。
如下代码,自定义RiverBeanFactoryPostProcessor,修改bean定义由单例改为原型。

1
2
3
4
5
6
7
8
9
10
11
@Component
public class RiverBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("RiverBeanFactoryPostProcessor...");
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("orderService");
beanDefinition.setScope("prototype");
}

}

测试代码:

1
2
3
@Component
public class OrderService {
}
1
2
3
4
5
6
7
8
9
10
@ComponentScan("cn.river.spring")
public class AppConfig {

public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println(context.getBean("orderService"));
System.out.println(context.getBean("orderService"));
System.out.println(context.getBean("orderService"));
}
}

6、BeanDefinitionRegistryPostProcessor

该接口定义如下:

1
2
3
4
5
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

该接口继承自BeanFactoryPostProcessor,具有BeanFactoryPostProcessor的功能,还兼具BeanDefinition注册的功能。
通过实现BeanDefinitionRegistryPostProcessor,可以将一个类注册为BeanDefinition,
这样不需要在类上加@Component注解,就可以从spring容器中获取该bean对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Component
public class RiverBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("postProcessBeanDefinitionRegistry...");
// 生成OrderService的bean定义
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
beanDefinition.setBeanClass(OrderService.class);
registry.registerBeanDefinition("orderService", beanDefinition);
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

}
}

7、ImportBeanDefinitionRegistrar

该接口定义如下:

1
2
3
4
5
public interface ImportBeanDefinitionRegistrar {

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

}

ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,它支持自定义BeanDefinition对象;
ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。
实现此接口的类会回调registerBeanDefinitions方法,将类注册到spring容器中。

1
2
3
4
5
6
7
8
9
10
public class RiverServiceRegistrar implements ImportBeanDefinitionRegistrar {

@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
//指定bean定义信息
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(UserService.class);
//注册一个bean指定bean名字
beanDefinitionRegistry.registerBeanDefinition("userService", rootBeanDefinition);
}
}
1
2
public class UserService {
}
1
2
3
4
5
6
7
8
9
10
11
@Import({RiverServiceRegistrar.class})
public class ImportBeanDefinitionTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(ImportBeanDefinitionTest.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
}

Spring整合Mybatis时也会用到此扩展点。

8、SmartLifecycle

Lifecycle接口定义如下:

1
2
3
4
5
6
public interface Lifecycle {

void start();
void stop();
boolean isRunning();
}

Lifecycle常用来管理一个组件的启动和停止;
Lifecycle表示的是ApplicationContext的生命周期,可以定义一个SmartLifecycle来监听ApplicationContext的启动和关闭。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Component
public class RiverLifecycle implements SmartLifecycle {
/**
* 组件的运行状态
*/
private volatile boolean running = false;

@Override
public void start() {
System.out.println("lifecycle start");
running = true;
}

@Override
public void stop() {
System.out.println("lifecycle stop");
running = false;
}

@Override
public boolean isRunning() {
System.out.println("lifecycle running state:" + running);
return running;
}
}

测试:

1
2
3
4
5
6
7
@ComponentScan("cn.river.spring")
public class LifecycleTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LifecycleTest.class);
context.close();
}
}

9、FactoryBean

FactoryBean是Spring容器实例化bean逻辑的扩展点。

接口定义如下:

1
2
3
4
5
6
7
8
9
10
11
public interface FactoryBean<T> {

T getObject() throws Exception;

Class<?> getObjectType();

default boolean isSingleton() {
return true;
}

}

一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean 。
在某些情况下,实例化bean过程比较复杂,Spring为此提供了FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。
后面又提供了@Configration和@Bean这种方式,一定程度上可以替代FactoryBean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class RiverFactoryBean implements FactoryBean {

@Override
public Object getObject() throws Exception {
return new UserBean();
}

@Override
public Class<?> getObjectType() {
return UserBean.class;
}

@Override
public boolean isSingleton() {
return true;
}
}
1
2
public class UserBean {
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
@ComponentScan("cn.river.spring")
public class FactoryBeanTest {

public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(FactoryBeanTest.class);
UserBean bean = (UserBean) context.getBean("riverFactoryBean");
System.out.println(bean);
Object fb = context.getBean("&riverFactoryBean");
System.out.println(fb);
}

}

10、ApplicationListener

ApplicationContext事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。
ApplicationListener接口定义如下:

1
2
3
4
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

void onApplicationEvent(E event);
}

如果容器中有一个ApplicationListener的Bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListener的Bean将自动被触发。
Spring中有一些内置的事件,当完成摸个动作时会触发某些事件,如ContextRefreshedEvent事件,当所有的bean都初始化完成并被成功装载后会触发该事件,实现ApplicationListener接口可以收到监听动作。
我们也可以自定义事件监听,来完成某些业务逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class MsgApplicationListener implements ApplicationListener<MsgEvent> {

@Override
public void onApplicationEvent(MsgEvent event) {
System.out.println(event.getSource());
}

@EventListener
public void handle(MsgEvent event) {
System.out.println("注解监听: " + event);
}
}

自定义事件,继承ApplicationEvent

1
2
3
4
5
6
public class MsgEvent extends ApplicationEvent {

public MsgEvent(Object source) {
super(source);
}
}

测试代码:

1
2
3
4
5
6
7
8
9
@ComponentScan("cn.river.spring")
public class ApplicationListenerDemo {

public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationListenerDemo.class);
MsgEvent msgEvent = new MsgEvent("发送短信");
context.publishEvent(msgEvent);
}
}