你应该知道的那些耳熟能详的 Spring 框架扩展点

好记忆不如烂笔头,能记下点东西,就记下点,有时间拿出来看看,也会发觉不一样的感受.

目录

 全局异常处理

自定义拦截器

获取 Spring 容器对象

导入配置

项目启动时的附加功能

修改 BeanDefinition

初始化方法

在初始化 Bean 前后添加逻辑

在关闭容器之前添加操作

自定义作用域


Spring 框架具有强大的扩展性,通过各种扩展点可以实现丰富的自定义功能,提升开发效率和灵活性。

当我们提到 Spring 时,映入脑海的是 IOC(控制反转)和 AOP(面向切面编程)。

Spring 具有很强的扩展性。许多第三方应用程序,如 rocketmq、mybatis、redis 等,都可以轻松集成到 Spring 系统中。让我们来看看 Spring 的那些常用的扩展点。

1. 全局异常处理

描述

全局异常处理用于统一处理项目中的异常,避免在每个接口中重复编写异常处理代码,提升代码的可维护性和用户体验。

使用场景

当项目中有大量接口时,统一处理异常,避免重复代码。

示例代码

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public String handleException(Exception e) {
        if (e instanceof ArithmeticException) {
            return "params error";
        }
        if (e instanceof Exception) {
            return "Internal server exception";
        }
        return null;
    }
}

2. 自定义拦截器

描述

自定义拦截器用于在请求处理过程中插入自定义逻辑,例如权限验证、日志记录等。

使用场景

需要在请求处理前后执行某些逻辑,如权限校验、日志记录。

示例代码

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("===Authority Verification===");
        return true;
    }
}

@Configuration
public class WebAuthConfig extends WebMvcConfigurerAdapter {
    @Bean
    public AuthInterceptor getAuthInterceptor() {
        return new AuthInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthInterceptor());
    }
}

3. 获取 Spring 容器对象

描述

通过实现特定接口,可以在 Spring 容器中获取 BeanFactory 或 ApplicationContext,从而操作 Spring 容器。

使用场景

需要动态获取 Spring 容器中的 Bean 或操作容器。

示例代码

使用 BeanFactoryAware
@Service
public class StudentService implements BeanFactoryAware {
    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public void add() {
        Student student = (Student) beanFactory.getBean("student");
    }
}
使用 ApplicationContextAware
@Service
public class StudentService2 implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void add() {
        Student student = (Student) applicationContext.getBean("student");
    }
}

4. 导入配置

描述

通过 @Import 注解可以导入其他配置类或普通类到 Spring 容器中。

使用场景

需要将其他类或配置类导入到 Spring 容器中。

示例代码

导入普通类
public class A {
}

@Import(A.class)
@Configuration
public class TestConfiguration {
}
导入带有 @Configuration 注解的配置类
public class A {
}

public class B {
}

@Import(B.class)
@Configuration
public class AConfiguration {
    @Bean
    public A a() {
        return new A();
    }
}

@Import(AConfiguration.class)
@Configuration
public class TestConfiguration {
}
使用 ImportSelector
public class AImportSelector implements ImportSelector {
    private static final String CLASS_NAME = "com.demo.cache.service.A";

    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{CLASS_NAME};
    }
}

@Import(AImportSelector.class)
@Configuration
public class TestConfiguration {
}
使用 ImportBeanDefinitionRegistrar
public class AImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(A.class);
        registry.registerBeanDefinition("a", rootBeanDefinition);
    }
}

@Import(AImportBeanDefinitionRegistrar.class)
@Configuration
public class TestConfiguration {
}

5. 项目启动时的附加功能

描述

通过实现 ApplicationRunnerCommandLineRunner 接口,可以在项目启动时执行自定义逻辑。

使用场景

需要在项目启动时加载系统参数、初始化资源等。

示例代码

@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("项目启动时执行附加功能,加载系统参数...");
        Properties properties = new Properties();
        try (InputStream inputStream = new FileInputStream("application.properties")) {
            properties.load(inputStream);
            String systemParam = properties.getProperty("system.param");
            System.out.println("加载的系统参数值为:" + systemParam);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

6. 修改 BeanDefinition

描述

通过实现 BeanFactoryPostProcessor 接口,可以在 Bean 实例化之前修改其定义。

使用场景

需要在 Bean 实例化之前修改其属性或行为。

示例代码

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.addPropertyValue("id", 123);
        beanDefinitionBuilder.addPropertyValue("name", "Dylan Smith");
        defaultListableBeanFactory.registerBeanDefinition("user", beanDefinitionBuilder.getBeanDefinition());
    }
}

7. 初始化方法

描述

通过 @PostConstruct 注解或实现 InitializingBean 接口,可以在 Bean 初始化时执行自定义逻辑。

使用场景

需要在 Bean 初始化时执行某些操作。

示例代码

使用 @PostConstruct
@Service
public class AService {
    @PostConstruct
    public void init() {
        System.out.println("===Initializing===");
    }
}
实现 InitializingBean 接口
@Service
public class BService implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("===Initializing===");
    }
}

8. 在初始化 Bean 前后添加逻辑

描述

通过实现 BeanPostProcessor 接口,可以在 Bean 初始化前后插入自定义逻辑。

使用场景

需要在 Bean 初始化前后执行某些操作。

示例代码

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof User) {
            ((User) bean).setUserName("Dylan Smith");
        }
        return bean;
    }
}

9. 在关闭容器之前添加操作

描述

通过实现 DisposableBean 接口或使用 @PreDestroy 注解,可以在 Spring 容器关闭时执行清理操作。

使用场景

需要在 Spring 容器关闭时释放资源或执行清理操作。

示例代码

@Service
public class DService implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy");
    }
}

10. 自定义作用域

描述

通过实现 Scope 接口,可以自定义 Bean 的作用域,满足特定场景的需求。

使用场景

默认作用域(如 singleton、prototype)无法满足需求时。

示例代码

实现 Scope 接口
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;
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
    }

    @Override
    public Object resolveContextualObject(String key) {
        return null;
    }

    @Override
    public String getConversationId() {
        return null;
    }
}
注入自定义 Scope
@Component
public class ThreadLocalBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcess
}

相知不迷路,来者皆是兄弟!
搜索微信公众号 :“codingba” or “码出精彩” 交朋友,有更多资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值