本文共 10079 字,大约阅读时间需要 33 分钟。
最近,我注意到越来越多的读者认可我的技术文章,这让我感到非常开心。许多读者希望我能分享更多关于Spring的知识点,尤其是那些在实际工作中能够派上用场的内容。经过几年的Spring开发经验积累,我决定将自己认为不错的知识点总结起来,为大家提供帮助。
在Spring开发过程中,获取容器对象是一个非常重要的操作。Spring提供了多种接口和方法可以实现这一功能。以下是几种常用的实现方式:
BeanFactoryAware是Spring中一个非常基础的接口,用于感知BeanFactory。通过实现该接口,我们可以在setBeanFactory方法中获取到Spring容器。
@Servicepublic class PersonService implements BeanFactoryAware { private BeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } public void add() { Person person = (Person) beanFactory.getBean("person"); }} ApplicationContextAware接口是BeanFactoryAware的扩展版本,用于感知ApplicationContext。通过实现setApplicationContext方法,我们可以获取到更全面的Spring容器。
@Servicepublic class PersonService2 implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public void add() { Person person = (Person) applicationContext.getBean("person"); }} ApplicationListener接口用于监听Spring上下文的变化。通过实现onApplicationEvent方法,我们可以在Spring容器刷新时获取到新的容器实例。
@Servicepublic class PersonService3 implements ApplicationListener{ private ApplicationContext applicationContext; @Override public void onApplicationEvent(ContextRefreshedEvent event) { applicationContext = event.getApplicationContext(); } public void add() { Person person = (Person) applicationContext.getBean("person"); }}
Spring提供了多种方式来初始化Bean。以下是几种常用的方法:
@PostConstruct注解是一个非常方便的初始化Bean的方法。通过在方法上加注解,可以在Bean初始化后执行自定义逻辑。
@Servicepublic class AService { @PostConstruct public void init() { System.out.println("===初始化==="); }} InitializingBean接口提供了一个afterPropertiesSet方法,可以在Bean初始化后执行自定义逻辑。
@Servicepublic class BService implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { System.out.println("===初始化==="); }} Spring默认提供了两种Scope:Singleton和Prototype。然而,在某些场景下,我们可能需要自定义自己的Scope。以下是一个常见的实现方式:
如果我们需要在同一个线程中获取相同的Bean实例,可以定义一个ThreadLocalScope:
public class ThreadLocalScope implements Scope { private static final ThreadLocal THREAD_LOCAL_SCOPE = new ThreadLocal(); @Override public Object get(String name, ObjectFactory objectFactory) { Object value = THREAD_LOCAL_SCOPE.get(); if (value != null) { return value; } Object object = objectFactory.getObject(); THREAD_LOCAL_SCOPE.set(object); return object; } @Override public Object remove(String name) { THREAD_LOCAL_SCOPE.remove(); return null; } // 其他方法可以根据需求实现} 通过BeanFactoryPostProcessor来注册自定义Scope:
@Componentpublic class ThreadLocalBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { beanFactory.registerScope("threadLocalScope", new ThreadLocalScope()); }} 在需要ThreadLocalScope的Bean上使用@Scope注解:
@Scope("threadLocalScope")@Servicepublic class CService { public void add() {}} FactoryBean是一个非常重要的接口,在Spring源码中被广泛使用。以下是如何定义和使用FactoryBean的示例:
实现FactoryBean接口,可以自定义Bean的初始化逻辑:
@Componentpublic class MyFactoryBean implements FactoryBean { @Override public Object getObject() throws Exception { String data1 = buildData1(); String data2 = buildData2(); return buildData3(data1, data2); } private String buildData1() { return "data1"; } private String buildData2() { return "data2"; } private String buildData3(String data1, String data2) { return data1 + data2; }} 通过BeanFactory获取FactoryBean实例:
@Servicepublic class MyFactoryBeanService implements BeanFactoryAware { private BeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } public void test() { Object myFactoryBean = beanFactory.getBean("myFactoryBean"); System.out.println(myFactoryBean); Object myFactoryBean1 = beanFactory.getBean("&myFactoryBean"); System.out.println(myFactoryBean1); }} Spring支持多种类型转换器。以下是一个常见的类型转换场景:
假设我们需要将字符串日期转换为Date对象:
public class DateConverter implements Converter{ private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public Date convert(String source) { if (source != null && !"".equals(source)) { try { simpleDateFormat.parse(source); } catch (ParseException e) { e.printStackTrace(); } } return null; }}
通过WebMvcConfigurerAdapter注入类型转换器:
@Configurationpublic class WebConfig extends WebMvcConfigurerAdapter { @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new DateConverter()); }} Spring MVC拦截器是处理Web请求的重要组件。以下是一个简单的权限校验拦截器:
public class AuthInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestUrl = request.getRequestURI(); if (checkAuth(requestUrl)) { return true; } return false; } private boolean checkAuth(String requestUrl) { System.out.println("===权限校验==="); return true; }} 通过WebMvcConfigurerAdapter注册拦截器:
@Configurationpublic class WebAuthConfig extends WebMvcConfigurerAdapter { @Bean public AuthInterceptor getAuthInterceptor() { return new AuthInterceptor(); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthInterceptor()); }} Enable注解是一种非常方便的开关方式。以下是一个自定义开关的实现:
public class LogFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("记录请求日志"); chain.doFilter(request, response); System.out.println("记录响应日志"); } @Override public void destroy() { }} @Configurationpublic class LogFilterWebConfig { @Bean public LogFilter timeFilter() { return new LogFilter(); }} @Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(LogFilterWebConfig.class)public @interface EnableLog {} 使用GlobalExceptionHandler实现统一异常处理:
@RestControllerAdvicepublic class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public String handleException(Exception e) { if (e instanceof ArithmeticException) { return "数据异常"; } if (e instanceof Exception) { return "服务器内部异常"; } return null; }} Spring提供了@Async注解,使得异步编程变得更加简便:
@Servicepublic class PersonService { @Async public String get() { System.out.println("===add=="); return "data"; }} @Configurationpublic class ThreadPoolConfig { @Value("${thread.pool.corePoolSize:5}") private int corePoolSize; @Value("${thread.pool.maxPoolSize:10}") private int maxPoolSize; @Value("${thread.pool.queueCapacity:200}") private int queueCapacity; @Value("${thread.pool.keepAliveSeconds:30}") private int keepAliveSeconds; @Value("${thread.pool.threadNamePrefix:ASYNC_}") private String threadNamePrefix; @Bean public Executor MessageExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(corePoolSize); executor.setMaxPoolSize(maxPoolSize); executor.setQueueCapacity(queueCapacity); executor.setKeepAliveSeconds(keepAliveSeconds); executor.setThreadNamePrefix(threadNamePrefix); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; }} Spring Caffeine缓存实现:
org.springframework.boot spring-boot-starter-cache com.github.ben-manes.caffeine caffeine 2.6.0
@Configuration@EnableCachingpublic class CacheConfig { @Bean public CacheManager cacheManager() { CaffeineCacheManager cacheManager = new CaffeineCacheManager(); Caffeine caffeine = Caffeine.newBuilder() .expireAfterWrite(10, TimeUnit.SECONDS) .maximumSize(1000); cacheManager.setCaffeine(caffeine); return cacheManager; }} @Servicepublic class CategoryService { @Cacheable(value = "category", key = "#type") public CategoryModel getCategory(Integer type) { return getCategoryByType(type); } private CategoryModel getCategoryByType(Integer type) { System.out.println("根据不同的type:" + type + "获取不同的分类数据"); CategoryModel categoryModel = new CategoryModel(); categoryModel.setId(1L); categoryModel.setParentId(0L); categoryModel.setName("电器"); categoryModel.setLevel(3); return categoryModel; }} 如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描下发二维码关注一下,您的支持是我坚持写作最大的动力。
关注公众号:【苏三说技术】,在公众号中回复:面试、代码神器、开发手册、时间管理有超赞的粉丝福利,另外回复:加群,可以跟很多BAT大厂的前辈交流和学习。
转载地址:http://laxzz.baihongyu.com/