博客
关于我
spring中这些编程技巧,真的让我爱不释手
阅读量:403 次
发布时间:2019-03-05

本文共 10079 字,大约阅读时间需要 33 分钟。

Spring技术深度探索:从容器到高级功能

最近,我注意到越来越多的读者认可我的技术文章,这让我感到非常开心。许多读者希望我能分享更多关于Spring的知识点,尤其是那些在实际工作中能够派上用场的内容。经过几年的Spring开发经验积累,我决定将自己认为不错的知识点总结起来,为大家提供帮助。


一、如何获取Spring容器对象

在Spring开发过程中,获取容器对象是一个非常重要的操作。Spring提供了多种接口和方法可以实现这一功能。以下是几种常用的实现方式:

1. 实现BeanFactoryAware接口

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");    }}

2. 实现ApplicationContextAware接口

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");    }}

3. 实现ApplicationListener接口

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"); }}

二、如何初始化Bean

Spring提供了多种方式来初始化Bean。以下是几种常用的方法:

1. 使用@PostConstruct注解

@PostConstruct注解是一个非常方便的初始化Bean的方法。通过在方法上加注解,可以在Bean初始化后执行自定义逻辑。

@Servicepublic class AService {    @PostConstruct    public void init() {        System.out.println("===初始化===");    }}

2. 实现InitializingBean接口

InitializingBean接口提供了一个afterPropertiesSet方法,可以在Bean初始化后执行自定义逻辑。

@Servicepublic class BService implements InitializingBean {    @Override    public void afterPropertiesSet() throws Exception {        System.out.println("===初始化===");    }}

三、自定义自己的Scope

Spring默认提供了两种Scope:Singleton和Prototype。然而,在某些场景下,我们可能需要自定义自己的Scope。以下是一个常见的实现方式:

1. 定义ThreadLocalScope

如果我们需要在同一个线程中获取相同的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;    }        // 其他方法可以根据需求实现}

2. 注入自定义Scope到Spring容器

通过BeanFactoryPostProcessor来注册自定义Scope:

@Componentpublic class ThreadLocalBeanFactoryPostProcessor implements BeanFactoryPostProcessor {    @Override    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {        beanFactory.registerScope("threadLocalScope", new ThreadLocalScope());    }}

3. 使用自定义Scope

在需要ThreadLocalScope的Bean上使用@Scope注解:

@Scope("threadLocalScope")@Servicepublic class CService {    public void add() {}}

四、别说FactoryBean没用

FactoryBean是一个非常重要的接口,在Spring源码中被广泛使用。以下是如何定义和使用FactoryBean的示例:

1. 定义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;    }}

2. 获取FactoryBean

通过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支持多种类型转换器。以下是一个常见的类型转换场景:

1. 定义DateConverter

假设我们需要将字符串日期转换为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; }}

2. 注入类型转换器

通过WebMvcConfigurerAdapter注入类型转换器:

@Configurationpublic class WebConfig extends WebMvcConfigurerAdapter {    @Override    public void addFormatters(FormatterRegistry registry) {        registry.addConverter(new DateConverter());    }}

六、Spring MVC拦截器

Spring MVC拦截器是处理Web请求的重要组件。以下是一个简单的权限校验拦截器:

1. 实现HandlerInterceptorAdapter

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;    }}

2. 注册拦截器

通过WebMvcConfigurerAdapter注册拦截器:

@Configurationpublic class WebAuthConfig extends WebMvcConfigurerAdapter {    @Bean    public AuthInterceptor getAuthInterceptor() {        return new AuthInterceptor();    }        @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(new AuthInterceptor());    }}

七、Enable开关真香

Enable注解是一种非常方便的开关方式。以下是一个自定义开关的实现:

1. 定义LogFilter

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() {    }}

2. 注册LogFilter

@Configurationpublic class LogFilterWebConfig {    @Bean    public LogFilter timeFilter() {        return new LogFilter();    }}

3. 定义EnableLog注解

@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注解,使得异步编程变得更加简便:

1. 使用@Async注解

@Servicepublic class PersonService {    @Async    public String get() {        System.out.println("===add==");        return "data";    }}

2. 定义线程池

@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缓存实现:

1. 引入Caffeine依赖

org.springframework.boot
spring-boot-starter-cache
com.github.ben-manes.caffeine
caffeine
2.6.0

2. 配置CacheManager

@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;    }}

3. 使用@Cacheable注解

@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/

你可能感兴趣的文章
Objective-C实现使用 ziggurat() 作为 OpenMP 并行程序中的随机数生成器 (RNG)(附完整源码)
查看>>
Objective-C实现使用DisjointSet 检测无向循环算法(附完整源码)
查看>>
Objective-C实现使用数组实现约瑟夫环(附完整源码)
查看>>
Objective-C实现使用管道重定向进程输入输出(附完整源码)
查看>>
Objective-C实现倒计时(附完整源码)
查看>>
Objective-C实现借记款项功能(附完整源码)
查看>>
Objective-C实现八进制转十进制算法(附完整源码)
查看>>
Objective-C实现关系矩阵A和B的乘积(附完整源码)
查看>>
Objective-C实现关系矩阵乘法(附完整源码)
查看>>
Objective-C实现关系矩阵乘法(附完整源码)
查看>>
Objective-C实现关键字移位字母表密码算法(附完整源码)
查看>>
Objective-C实现内存映射文件(附完整源码)
查看>>
Objective-C实现内存泄露检查(附完整源码)
查看>>
Objective-C实现内格尔·施雷肯伯格算法(附完整源码)
查看>>
Objective-C实现冒泡排序(附完整源码)
查看>>
Objective-C实现几何级数的总和算法 (附完整源码)
查看>>
Objective-C实现凯撒密码算法(附完整源码)
查看>>
Objective-C实现凸多边形的凸包问题算法(附完整源码)
查看>>
Objective-C实现分块查找算法(附完整源码)
查看>>
Objective-C实现分块查找算法(附完整源码)
查看>>