基础依赖
Spring IOC 依赖关系构成:
初始化容器(IOC)
@Configuration
@ComponentScan("org.example.demo")
public class TestApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestApplication.class);
TestService service = context.getBean("testService", TestService.class);
service.running();
context.close();
}
}
在上述案例中,AnnotationConfigApplicationContext
读取 TestApplication.class
中的配置元数据,从而构造了一个 Spring IOC容器。
其中 @Configuration
表示该类是一个配置文件,@ComponentScan("org.example.demo")
表示需要IOC进行管理的类路径
而 context.getBean("testService", TestService.class);
表示,从IOC容器中获取指定的实例(当然,该实例是单例的)
依赖注入(DI)
由上一个案例推断,我们从容器中获取了 testService
@Service
public class TestService {
@Resource
private TestBean testBean;
public void running () {
System.out.println(testBean.getMessage());
}
}
@Getter
@Component
public class TestBean {
private String message;
}
首先,我们使用 @Service
和 @Component
标明 TestService 与 TestBean 需要被 IOC 扫描并管理
之后,@Resource
负责将 TestBean 使用反射的原理注入,当然,我们也可以使用方法、构造函数的方式注入,但这里不概述
读取配置文件(Property)
pre-destroy = pre destroy in configuration
post-construct = post construct in configuration
bean-message = this is a test bean message
@Configuration
@ComponentScan("org.example.demo")
@PropertySource("classpath:/application.properties")
public class TestConfiguration {
@Value("${pre-destroy}")
private String preDestroy;
@Value("${post-construct}")
private String postConstruct;
}
@Configuration
@Import(TestConfiguration.class)
public class TestApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestApplication.class);
TestService service = context.getBean("testService", TestService.class);
service.running();
context.close();
}
}
这是一个相对而言较为复杂的案例,我们使用 @Import
导入了名叫 TestConfiguration 的配置类
而在 TestConfiguration 中,使用 @PropertySource("classpath:/application.properties")
读取了指定位置的 properties 文件
最终,我们可以使用 @Value("${pre-destroy}")
的方式,将 properties 中的配置项注入到指定变量
Bean 状态
我们将被 Spring IOC 管理的对象称为 Spring Bean
默认状态下,在构造 IOC 的时候,这些对象将被全部加载,并且全局只有一份,但这也可以被改变
@Service
@Scope("prototype")
public class TestService {
@Lazy
@Resource
private TestBean testBean;
public void running () {
System.out.println(testBean.getMessage());
}
}
上述案例中,@Scope("prototype")
表示 TestService 是非单例状态,即每次注入 TestService,均是全新的实例
而 @Lazy
表示懒加载,只有 TestBean 被使用时才会注入
自定义 Bean 性质
@Getter
@Component
public class TestBean implements ApplicationContextAware, BeanNameAware, BeanClassLoaderAware {
@Value("${bean-message}")
private String message;
@Value("${pre-destroy}")
private String preDestroy;
@Value("${post-construct}")
private String postConstruct;
@PreDestroy
private void preDestroy () {
System.out.println(preDestroy);
}
@PostConstruct
private void postConstruct () {
System.out.println(postConstruct);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("Gets application context by implements ApplicationContextAware");
}
@Override
public void setBeanName(String s) {
System.out.println("Gets bean name by implements ApplicationContextAware");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("Gets class loader by implements BeanClassLoaderAware");
}
}
这是一个较为特殊的案例,其中分为两部分,@PreDestroy
和 @PostConstruct
表示该类的生命周期函数,即销毁前调用、构造后调用。
另一部分,是来自实现的各种 Aware 接口,Aware 翻译后的意思是知道,代表实现了这类型接口,即可知道其对应的内容,例如:实现 ApplicationContextAware
接口的 setApplicationContext
函数后,可以得到一个 applicationContext
的对象,该对象可以让你知道 IOC 的上下文内容。
这里仅列举了部分 Aware,更多请前往官网查阅
扩展 IOC
Spring 提供了接口可以用来扩展 IOC
自定义 Bean
Spring 提供了一个叫做 BeanPostProcessor 的接口,它可以让你在全局范围内对 Bean 进行自定义
@Component
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.print("process bean of before initialization");
System.out.println("'" + beanName + "' created : " + bean.toString());
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.print("process bean of after initialization");
System.out.println("'" + beanName + "' created : " + bean.toString());
return bean;
}
}
自定义配置元数据
如果说 BeanPostProcessor 可以让我们在全局范围内处理 Bean 的话,那么 BeanFactoryPostProcessor 就是 BeanPostProcessor 的升级版,它允许你在全局范围内获取配置元数据
@Component
public class InstantiationTracingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
}
自定义 Bean 工厂
在实现 FactoryBean 后,我们自定义 Bean 的创建逻辑,甚至可以自定义这个 Bean 是否为单例
@Component
public class TestFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return null;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
附加功能
国际化
首先,在类路径下创建如下两个配置文件
# i18n/test_zn.properties
test = 这是一个 i18n 的测试信息 {0}
# i18n/test_en.properties
test = this is a i18n message
之后,我们配置一个 ResourceBundleMessageSource
用于实现国际化
@Configuration
@ComponentScan("org.example.demo")
@PropertySource("classpath:/application.properties")
public class TestConfiguration {
@Bean
public ResourceBundleMessageSource messageSource () {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasenames("i18n/test");
source.setDefaultEncoding("UTF-8");
return source;
}
}
@Service
public class TestService {
@Resource
private MessageSource messageSource;
public void running () {
System.out.println(messageSource.getMessage("test", null, Locale.ENGLISH));
System.out.println(messageSource.getMessage("test", new String[] { "替换的文字" }, Locale.CHINESE));
}
}
事件监听
首先,我们需要创建一个用于被触发的事件,和这个事件的监听器
public class TestEvent extends ApplicationEvent {
public TestEvent(Object source) {
super(source);
}
}
@Component
public class TestListener implements ApplicationListener<TestEvent> {
@Override
public void onApplicationEvent(TestEvent event) {
System.out.println("this is a test event listener");
}
}
之后,我们需要利用 ApplicationEventPublisherAware
来获取 ApplicationEventPublisher
将事件发布出去
@Service
public class TestService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
public void running () {
publisher.publishEvent(new TestEvent(this));
}
}
当然,我们也可以有一个简化版
@Service
public class TestService {
@Resource
private ApplicationEventPublisher publisher;
public void running () {
publisher.publishEvent(new TestEvent(this));
}
@EventListener(TestEvent.class)
public void testEventListener (TestEvent event) {
System.out.println("this is a test event listener");
}
}
在简化版中,ApplicationEventPublisher
使用 DI 依赖注入,并且不需要单独创建一个事件监听的类
基于 Web 创建 IOC
您可以使用 ContextLoaderListener 注册 ApplicationContext:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
这里默认使用 /WEB-INF/**/*Context.xml
作为配置文件
本文由 Nainu 创作,采用 知识共享署名4.0
国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Feb 21,2022