https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html
1.4 依赖
1.4.1 依赖注入(DI)
- DI是这样一个过程,对象仅通过(构造方法参数、工厂方法参数从工厂方法构造或返回对象实例化后设置的属性)来定义它们的依赖项。容易在生成bean之后注入这些依赖。这个过程将之前的流程反转了–即bean通过直接构造类来自行控制实例化或定位依赖。
- DI使代码更为简洁,对象只提供它们的依赖,但不需要寻找依赖的位置(这些管理和寻找都由容器做好了)。
(1)基于构造器的依赖注入
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on a MovieFinder
private MovieFinder movieFinder;
// a constructor so that the Spring container can inject a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
(2)基于setter的依赖注入
- 循环依赖:beanA构造器参数依赖beanB,同时beanB也依赖A,IOC容器抛出BeanCurrentlyInCreationException-----一种解决方式是使用setter注入提到构造器注入
- spring会尽可能迟的设置属性和解析依赖,直到bean正在生成完成。因此spring可能加载成功,但真正请求bean时则抛出错误(比如bean缺少属性)。
- 如果没有循环依赖,多个组合bean会注入一个独立的bean,其中的每个组合bean在次注入之前都会完成配置。比如说,A依赖B,当B作用A之前会先自行配置完成。
1.4.2 依赖和配置的细节
- 如果A依赖B,那么B相当于A的一个属性。通xml的“depends-on”配置
1.4.3 懒加载(Lazy-initialized)
- 默认情况下,在初始化过程中,ApplicationContext的实现类会积极积加载所有的单例类。通常这种预先实例化是需要的,因为配置和环境的错误会立即发现,而不用等很久之后。如果不想这么做,可以将bean标记为”lazy-initialized“来阻止单例类的预先实例化。
- 但如果正常bean依赖于懒加载bean时,ApplicationContext也会执行预先实例化。
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
1.4.5 Autowiring Collaborators
1.4.6 方法注入
- 通常情况下容器里都是单例bean。当单例bean与非单例bean组合成非单例bean时,需要显式控制依赖,通过将一个bean定义为另一个bean的熟悉。
1.5 bean模式
1.5.1 单例模式(Singleton)
- spring容器中bean默认模式。容器中只会有一个bean实例(对所有的请求、依赖都一样);用于无状态的bean;spring容器完全管理单例bean的生命周期(默认是在关闭容器时销毁bean,可以自定义销毁逻辑)
1.5.2 Prototype模式
- 每次对该bean的请求都会创建一个新实例,用于有交互状态的bean
- spring不会完全管理Prototype模式bean的生命周期,一旦创建就由client负责,需要client负责资源清理(或者JVM内存回收)。
- 类似于Java中的new关键字,只创建,需要自己决定销毁。
1.5.3 单例与Prototype模式bean的依赖
- 对于一个依赖PrototypeBean的单例bean,容器会先实例化一个组合PrototypeBean,然后再用PrototypeBean注入到另一个单例Bean,这个单例Bean才对外。
1.6 定制化bean的特性
1.6.1 Bean生命周期
控制生命周期的按照方式
- InitializingBean 和 DisposableBean回调接口
- 自定义init() and destroy() 方法
- @PostConstruct and @PreDestroy 注解
初始化执行次序:
@PostConstruct—InitializingBean接口的afterPropertiesSet()方法–(BeanPostProcessor的回调方法)–自定义init方法(…)@PreDestroy—DisposableBean接口的destroy方法—自定义destroy方法 - 不建议使用InitializingBean接口,建议使用@Bean中的“initMethod”属性
- 不建议使用DisposableBean接口,建议使用@Bean中的“destroyMethod”属性
1.8.1 通过BeanPostProcessor自定义Bean
- 如果想在Spring容器完成实例化和bean初始化后实现自定义逻辑,可以实现BeanPostProcessor的回调方法
- Spring容器实例化bean,BeanPostProcessor使bean开始工作
1.8.2 通过BeanFactoryPostProcessor自定义配置元数据
1.8.3 通过FactoryBean自定义实例化逻辑
1.9 基于注解的容器配置
注解是否优于xml配置?
- 各有优劣,取决于具体情况
- 注解实现更为简洁和精准
- xml可以免编译执行,同时依赖注入更集中化,在一些场合更适合
- 两者同时出现时,xml会覆盖注解(注解先生效,xml在后面生效会覆盖注解)
1.9.1 @Required
1.9.2 @Autowired
1.9.3 @Primary
1.9.4 @Qualifier
1.9.6 CustomAutowireConfigurer
- 是一种BeanFactoryPostProcessor,可以注册自定义的qualifier注解类型
1.9.7 @Resource(JDK5、6中使用较多)
1.9.8 @PostConstruct and @PreDestroy
1.10 Classpath扫描和组件管理
1.10.1 @Component等
- @Component是普通的spring组织的注解,@Repository, @Service, and @Controller是特定应用场景下对@Component的专业化实现。
1.10.2 组合注解
- @RestController相当于@Controller and @ResponseBody的组合
1.10.3 自动类探测,注册bean
- 使用@ComponentScan 修饰@Configuration类,其中的basePackages属性为类所在的父package
- 使用@ComponentScan时,AutowiredAnnotationBeanPostProcessor会被默认调用(???)。
@ComponentScan(basePackages = "org.example")
@ComponentScan("org.example")
1.10.4 使用Filters来自定义扫描
- 设置:useDefaultFilters选项
@Configuration
@ComponentScan(basePackages = "org.example",
includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
excludeFilters = @Filter(Repository.class))
public class AppConfig {
...
}
1.10.5 在Component中定义Bean元数据(待深化)
- 使用@Bean注解修饰方法
- @Bean可修饰静态方法,使得他们被调用时不会再生成所包含的配置(为了安全起见)
- 静态@Bean方法的调用不会被Spring容器所拦截,这是由于CGLIB中子类只能覆盖非static类
- As a consequence, a direct call to another @Bean method has standard Java semantics, resulting in an independent instance being returned straight from the factory method itself.
- 通常情况下,@Bean修饰的方法不能声明为private以及final,因为他们需要是可覆盖的。
1.10.6 命名可自探测的Component
- 这类Component通过BeanNameGenerator生成,可以自定义该接口的实现
1.11 使用JSR 330注解
1.11.1 @Inject and @Named
- 可以实现@Autowired功能,默认byType注入
- 如果需要nyName注入,则使用@Name
1.15 ApplicationContext的额外功能
1.15.1 使用MessageSource实现跨语言
1.15.2 标准化好自定义事件
- 通过ApplicationEvent类和ApplicationListener接口可以实现ApplicationContext的事件处理。如果一个context中的bean实现了ApplicationListener接口,那么每次向ApplicationContext发布ApplicationEvent,这个bean总会感知到。这是标准的“观察者”模式
- 在spring-4.2之后,这种事件架构被极大改进了,可以通过注解实现而不是随意的发布event(也就是说,一个对象不在必须继承自ApplicationEvent)。一旦该对象被发布,我们会抓取它,并把它作为一个事件发给用户。
- 用户也可以实现和发布自定义事件。
基于注解的事件Listeners
public class BlackListNotifier {
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
@EventListener({BlackListEvent.class})
public void processBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
}
- 也可以支持通过SpEL语句定义的condition属性
@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlackListEvent(BlackListEvent blEvent) {
// notify appropriate parties via notificationAddress...
}
- 如果需要通过另一事件的处理结果来发送事件,可以改变方法,返回将要发布的事件。
@EventListener
public ListUpdateEvent handleBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress and
// then publish a ListUpdateEvent...
}
- 这个方法在处理每一个BlackListEvent时,都会发布一个新的ListUpdateEvent。
异步Listener
- 如果需要listener异步处理事件,可以使用@Async注解
@EventListener
@Async
public void processBlackListEvent(BlackListEvent event) {
// BlackListEvent is processed in a separate thread
}
有序Listener
@EventListener
@Order(42)
public void processBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
泛型事件
- 使用同一个Event处理不同的事件对象
@EventListener
public void onPersonCreated(EntityCreatedEvent<Person> event) {
...
}
public class EntityCreatedEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {
public EntityCreatedEvent(T entity) {
super(entity);
}
@Override
public ResolvableType getResolvableType() {
return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getSource()));
}
}