Spring 常用配置
2.1 Bean的scope
@Scope 注解,情况分以下几种:
- Singleton:单例,spring 的默认配置,全容器共享一个实例
- Prototype:每次调用新建一个bean实例,举例 @Scope("prototype")
- Request:web项目中,每一个 http request 新建一个bean实例
- Session:web项目中,每一个 http session 新建一个bean实例
- GlobalSession:仅用于portal应用,每一个global http session 新建一个bean实例
2.2 SpringEL和资源利用
-
@Value注解
-
#与$符号的区分
2.3 Bean的初始化和销毁
两种方式如下:
- Java配置方式:使用@Bean 的 initMethod 和 destoryMethod 方法,相当于 xml 配置的 init-method 和 destroy-method
- 注解方式:利用 JSR-250 的 @PostConstruct 和 @ PreDestroy 。需要另外引入 JSR-250 依赖。
备注:可深入了解一下 spring bean 的生命周期。
2.4 Profile
- 通过设定 Environment 的 ActiveProfiles 来设定当前 context 需要使用的配置环境。在开发中使用 @Profile 注解类或方法,达到在不同情况下选择实例化不同的bean。
- 通过设定jvm的 spring.profiles.active 参数来设置配置环境。
- Web项目设置在Servlet的 context parameter 中,注 servlet2.5 及以下与 servlet 3.0 及以上 设置方式有区别。
总结:使用哪种方式去区分项目部署环境需要视情况而定。实际项目中,第二种方式比较适合线上环境部署的场景,把环境判断抽离出代码层面,盲猜一波 spring-boot 自动配置的 profile 也是基于此模块,拭目以待。
2.5 事件(Application Event)
支持容器内 bean 与 bean 之间的消息通信,基本流程如下:
- 自定义事件,继承 ApplicationEvent
- 定义事件监听器,实现 ApplicationListener。指定监听事件类型,onApplicationEvent 对消息进行受理。
- 使用容器发布事件。spring 上下文 AppcalitionContext 调用 publishEvent 发布事件。
Spring高级话题
3.1 Spring Aware
google 翻译:春天察觉
实际意义是 spring 提供 bean 与 spring 框架耦合的一套机制,提供如下 Aware 接口(了解主要作用即可):
- BeanNameAware
- BeanFactoryAware
- ApplicationContextAware
- MessageSourceAware
- ApplicationEventPublishAware
- ResourceLoadAware
3.2 多线程
Spring 通过 TaskExecutor 来实现 多线程 和 并发编程。备注,ThreadPoolTaskExecutor 是基于 线程池 的 TaskExecutor。涉及注解:@EnableAsync 、 @Async。示例如下:
配置类实现 AsyncConfigurer 接口并重写 getAsyncExecutor 方法,返回 ThreadPoolTaskExecutor:
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
/**
* @author akazc
* @date 2020/8/23 14:58
*/
@EnableAsync
@Configuration
public class TaskExecutorConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(10);
taskExecutor.setQueueCapacity(25);
taskExecutor.initialize();
return taskExecutor;
}
}
备注:需要补充一下线程池的知识点
3.3 计划任务
涉及注解:@EnableScheduling、@Scheduled
3.4 条件注解@Conditional
涉及注解:@Conditional。涉及接口:org.springframework.context.annotation.Condition
据说springboot中大量应用条件注解,拭目以待
3.5 组合注解与元注解
组合注解:@Configuration: @Component + @Bean , 差不多就这个意思吧
3.6 @Enable*注解的工作原理
常见 Enable*注解
@EnableAspectJAutoProxy 开启 AspectJ 自动代理的支持
@EnableAsync 开启异步方法支持
@EnableScheduling 开启计划任务的支持
@EnbaleWebMvc 开启 WebMVC 配置支持
@EnableConfigurationProperties 开启对 @ConfigurationProperties 注解配置 bean 支持
@EnbaleJpaRepositories 开启对 Spring Data JPA Repository 支持
@EnableTransactionManagement 开启注解式事务支持
@EnableCaching 开启注解式缓存支持
@Import注解导入配置方式的三种类型
直接导入配置类
直接注册一个bean,示例:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({SchedulingConfiguration.class})
@Documented
public @interface EnableScheduling {
}
@Configuration
@Role(2)
public class SchedulingConfiguration {
public SchedulingConfiguration() {
}
@Bean(
name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"}
)
@Role(2)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
依据条件选择配置类
根据选择器来注册bean。即实现 ImportSelector 重写 selectImports 方法,示例:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AsyncConfigurationSelector.class})
public @interface EnableAsync {
Class<? extends Annotation> annotation() default Annotation.class;
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default 2147483647;
}
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME = "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
public AsyncConfigurationSelector() {
}
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch(adviceMode) {
case PROXY:
return new String[]{ProxyAsyncConfiguration.class.getName()};
case ASPECTJ:
return new String[]{"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration"};
default:
return null;
}
}
}
public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode";
public AdviceModeImportSelector() {
}
protected String getAdviceModeAttributeName() {
return "mode";
}
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
Class<?> annType = GenericTypeResolver.resolveTypeArgument(this.getClass(), AdviceModeImportSelector.class);
Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (attributes == null) {
throw new IllegalArgumentException(String.format("@%s is not present on importing class '%s' as expected", annType.getSimpleName(), importingClassMetadata.getClassName()));
} else {
AdviceMode adviceMode = (AdviceMode)attributes.getEnum(this.getAdviceModeAttributeName());
String[] imports = this.selectImports(adviceMode);
if (imports == null) {
throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
} else {
return imports;
}
}
}
@Nullable
protected abstract String[] selectImports(AdviceMode var1);
}
动态注册bean
运行时自动添加bean到已有配置类。即实现 ImportBeanDefinitionRegistrar 接口,重写 registerBeanDefinitions 方法。示例:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
AspectJAutoProxyRegistrar() {
}
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
3.7 测试
SpringMVC 基础
4.4 SpringMVC基本配置
核心
核心类:WebMvcConfigurerAdapter (5.X 版本已弃用继承该类,改为实现 WebMvcConfigurer 或继承 WebMvcConfigurationSupport,大同小异,可看下源码理解)
核心注解:@EnableWebMvc
理解 WebMvcConfigurer 源码:
public interface WebMvcConfigurer {
// 路径匹配参数配置
default void configurePathMatch(PathMatchConfigurer configurer) {
// 示例:路径参数不可忽略 "."
// configurer.setUseSuffixPatternMatch(false);
}
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
default void addFormatters(FormatterRegistry registry) {
}
// 注册拦截器
default void addInterceptors(InterceptorRegistry registry) {
// 注册拦截器,集成 HandlerInterceptorAdapter 注册即可
// registry.addInterceptor(HandlerInterceptor.class);
}
// 添加静态资源映射
default void addResourceHandlers(ResourceHandlerRegistry registry) {
// 对外暴露的访问路径
// registry.addResourceHandler();
// 指定静态文件放置目录
// resgistry.addResourceLocations();
}
default void addCorsMappings(CorsRegistry registry) {
}
// 添加 view-controller,即快捷页面跳转
default void addViewControllers(ViewControllerRegistry registry) {
// 示例
// registry.addViewController("/index").setViewName("/index");
}
default void configureViewResolvers(ViewResolverRegistry registry) {
}
default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
}
default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
}
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
@Nullable
default Validator getValidator() {
return null;
}
@Nullable
default MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
@ControllerAdivice
顾名思义是 controller 的功能加强,目标是对于控制器的全局配置放置在统一个位置,主要有以下功能注解:
@ExpectionHandler:用于全局处理控制器里的异常
@InitBinder:设置WebDataBinder,用来自动绑定前台请求参数到Model中
@ModelAttribute:本来的作用是绑定键值对到model里,此处是让全局的@RequestMapping都能获得在此处设置的键值对
4.5 SpringMVC的高级配置
文件上传配置
主要bean:MultipartResolver
主要类:MultipartFile
HttpMessageConverter
HttpMessageConverter是用来处理 request 和 response 里的数据的。
- Spring内置的HttpMessageConverter:
- StringHttpMessageConverter 负责字符串类型的数据的读取或者写出
- ByteArrayHttpMessageConverter 负责二进制格式的读取或者写出
- ResourceHttpMessageConverter 负责资源文件的读取或者写出
- FormHttpMessageConverter 负责读取form提交的数据 application/x-www-form-urlencoded
- MappingJacksonHttpMessageConverter 负责json格式数据的读取或者写出
- 自定义HttpMessageConverter