偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

掌握Spring框架這十個擴展點,開發(fā)效率直接翻倍!

開發(fā) 架構(gòu)
攔截器是單例的,千萬別在里面定義成員變量存儲請求相關(guān)數(shù)據(jù),要用ThreadLocal來保證線程安全。另外注意攔截順序,多個攔截器的執(zhí)行順序可以通過@Order注解控制。

兄弟們,大家真的把Spring 框架用明白了嗎?很多人只停留在@Controller、@Service這些基礎(chǔ)注解上,卻不知道 Spring 藏著很多 "黑科技"—— 那些能讓你少寫千行代碼、輕松搞定復(fù)雜需求的擴展點。今天就帶你深挖 Spring 最實用的 10 個擴展點,看完這篇文章,同事看你代碼的眼神都會不一樣!

1. 全局異常處理:@RestControllerAdvice 拯救重復(fù)代碼

先說個扎心的場景:你辛辛苦苦寫了十個接口,每個接口都要寫一堆try-catch處理異常,就為了返回統(tǒng)一格式的錯誤信息。老板路過看了眼代碼:"小伙子,代碼不夠精煉??!" 你心里直呼冤枉,但又確實沒轍 —— 直到發(fā)現(xiàn)了@RestControllerAdvice這個神器。

這個擴展點本質(zhì)上是個增強版的@Component,專門用來處理全局異常。它能像漁網(wǎng)一樣捕獲整個應(yīng)用里拋出的異常,讓你從重復(fù)的異常處理代碼中解放出來。

@RestControllerAdvice
public class GlobalExceptionHandler {
    // 處理算術(shù)異常(比如除零錯誤)
    @ExceptionHandler(ArithmeticException.class)
    public ResultDTO handleArithmeticException(ArithmeticException e) {
        return ResultDTO.fail("數(shù)學(xué)不好別亂除:" + e.getMessage());
    }
    // 處理空指針異常
    @ExceptionHandler(NullPointerException.class)
    public ResultDTO handleNullPointerException(NullPointerException e) {
        return ResultDTO.fail("對象為空啦:" + e.getMessage());
    }
    // 處理所有未捕獲的異常
    @ExceptionHandler(Exception.class)
    public ResultDTO handleException(Exception e) {
        return ResultDTO.fail("系統(tǒng)開小差了:" + e.getMessage());
    }
}

用了這個擴展點后,你的業(yè)務(wù)代碼可以徹底告別try-catch:

@GetMapping("/divide")
public int divide(int a, int b) {
    // 這里只管業(yè)務(wù)邏輯,異常交給全局處理器
    return a / b;
}

當(dāng)用戶訪問/divide?a=10&b=0時,會自動返回:

{
  "code": 500,
  "msg": "數(shù)學(xué)不好別亂除:/ by zero",
  "data": null
}

核心價值:把異常處理代碼從業(yè)務(wù)邏輯中剝離,實現(xiàn) "一處定義,處處生效",代碼量直降 30%,維護成本大大降低。記住,優(yōu)秀的程序員懂得讓代碼各司其職。

2. 自定義攔截器:HandlerInterceptor 控制請求生死權(quán)

你有沒有遇到過這些需求:記錄接口響應(yīng)時間、驗證用戶登錄狀態(tài)、打印請求日志?如果每個接口都手動實現(xiàn)這些功能,怕是要寫到手軟。這時HandlerInterceptor攔截器就該登場了,它就像小區(qū)門口的保安,能在請求到達接口前、接口執(zhí)行后甚至請求完成時做一些通用處理。

實現(xiàn)攔截器分兩步:首先定義攔截器邏輯,然后注冊它。

// 1. 定義攔截器
public class LogInterceptor implements HandlerInterceptor {
    private static final Logger log = LoggerFactory.getLogger(LogInterceptor.class);
    private ThreadLocal<Long> startTime = new ThreadLocal<>();
    // 請求處理前調(diào)用(返回false則阻止請求繼續(xù))
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        startTime.set(System.currentTimeMillis());
        log.info("請求開始:{} {}", request.getMethod(), request.getRequestURI());
        // 這里可以做登錄驗證,比如:
        if (request.getSession().getAttribute("user") == null) {
            response.setStatus(401);
            return false;
        }
        return true;
    }
    // 接口執(zhí)行后調(diào)用(還沒返回給客戶端)
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, 
                         Object handler, ModelAndView modelAndView) {
        log.info("接口執(zhí)行完成:{}", request.getRequestURI());
    }
    // 整個請求完成后調(diào)用(包括視圖渲染)
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                              Object handler, Exception ex) {
        long cost = System.currentTimeMillis() - startTime.get();
        log.info("請求結(jié)束:{},耗時:{}ms", request.getRequestURI(), cost);
        startTime.remove(); // 清理ThreadLocal,避免內(nèi)存泄漏
    }
}
// 2. 注冊攔截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor())
                .addPathPatterns("/**") // 攔截所有路徑
                .excludePathPatterns("/login", "/register"); // 排除登錄注冊接口
    }
}

這個攔截器能幫你完成:

  • 接口訪問日志記錄
  • 接口響應(yīng)時間統(tǒng)計
  • 登錄狀態(tài)驗證
  • 接口訪問頻率限制

避坑指南:攔截器是單例的,千萬別在里面定義成員變量存儲請求相關(guān)數(shù)據(jù),要用ThreadLocal來保證線程安全。另外注意攔截順序,多個攔截器的執(zhí)行順序可以通過@Order注解控制。

3. 容器對象獲?。篈pplicationContextAware 拿 Bean 不求人

有沒有過這種經(jīng)歷:在非 Spring 管理的類里想調(diào)用 Spring 的 Bean,結(jié)果翻遍全網(wǎng)都找不到好辦法?比如在工具類里需要用到UserService,但工具類又沒法用@Autowired注入。這時候ApplicationContextAware就是你的救星,它能讓你直接拿到 Spring 容器,想要什么 Bean 自己拿!

@Component
public class SpringContextHolder implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    // Spring會自動調(diào)用這個方法,把容器對象傳進來
    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        applicationContext = context;
    }
    // 獲取容器中的Bean
    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }
    // 根據(jù)名字獲取Bean
    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }
    // 判斷Bean是否存在
    public static boolean containsBean(String name) {
        return applicationContext.containsBean(name);
    }
}

有了這個工具類,隨時隨地獲取 Bean:

// 在普通工具類中使用Spring的Bean
public class UserUtil {
    public static User getUserById(Long id) {
        // 直接從容器拿UserService
        UserService userService = SpringContextHolder.getBean(UserService.class);
        return userService.getById(id);
    }
}

原理揭秘:Spring 在初始化 Bean 時,會檢查 Bean 是否實現(xiàn)了Aware接口家族,如果實現(xiàn)了,就會調(diào)用對應(yīng)的setXxx方法注入相關(guān)對象。除了ApplicationContextAware,常用的還有:

  • BeanNameAware:獲取 Bean 在容器中的名字
  • BeanFactoryAware:獲取 BeanFactory 對象
  • EnvironmentAware:獲取環(huán)境配置對象

注意事項:這個工具類一定要交給 Spring 管理(加@Component),否則 Spring 不會調(diào)用setApplicationContext方法。另外盡量避免濫用,能通過依賴注入解決的就不要直接拿容器。

4. 啟動初始化:CommandLineRunner 與 ApplicationRunner 預(yù)熱系統(tǒng)

你負責(zé)的項目有沒有這種需求:應(yīng)用啟動時需要加載字典數(shù)據(jù)到緩存、初始化數(shù)據(jù)庫連接池、或者發(fā)送服務(wù)啟動通知?總不能每次部署后手動執(zhí)行吧?Spring 提供了兩個專門用于啟動初始化的擴展點:CommandLineRunner和ApplicationRunner。

這哥倆功能差不多,區(qū)別在于參數(shù)類型:

// CommandLineRunner接收原始字符串?dāng)?shù)組參數(shù)
@Component
@Order(1) // 多個初始化器可以指定順序
public class CacheInitializer implements CommandLineRunner {
    @Autowired
    private DictService dictService;
    @Override
    public void run(String... args) throws Exception {
        log.info("開始加載字典緩存...");
        dictService.loadDictToCache();
        log.info("字典緩存加載完成!");
    }
}
// ApplicationRunner接收包裝后的ApplicationArguments
@Component
@Order(2)
public class ConfigPrinter implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("應(yīng)用啟動參數(shù):{}", args.getOptionNames());
        log.info("非選項參數(shù):{}", args.getNonOptionArgs());
    }
}

當(dāng)應(yīng)用啟動時,Spring 會自動調(diào)用這些實現(xiàn)類的run方法,而且支持通過@Order注解控制執(zhí)行順序(數(shù)字越小越先執(zhí)行)。實際應(yīng)用場景:

  • 加載熱點數(shù)據(jù)到本地緩存,提高首次訪問速度
  • 檢查數(shù)據(jù)庫表結(jié)構(gòu)是否存在,自動創(chuàng)建缺失的表
  • 注冊本服務(wù)到注冊中心
  • 發(fā)送應(yīng)用啟動成功的消息通知

小貼士:如果初始化邏輯可能耗時很長,可以考慮用@Async注解讓它異步執(zhí)行,避免阻塞應(yīng)用啟動。但要注意,異步初始化的邏輯不能是應(yīng)用啟動的必要條件。

5. 上下文初始化:ApplicationContextInitializer 預(yù)先配置環(huán)境

這個擴展點比較特殊,它的執(zhí)行時機非常早 —— 在 Spring 容器刷新之前。想象一下,你需要在應(yīng)用啟動初期就設(shè)置一些環(huán)境變量,或者動態(tài)注冊一些配置源,這時候ApplicationContextInitializer就能派上用場了。

它就像裝修房子前的設(shè)計規(guī)劃,在正式施工(容器刷新)前做好準(zhǔn)備工作:

public class CustomContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // 設(shè)置環(huán)境變量
        ConfigurableEnvironment env = applicationContext.getEnvironment();
        env.setActiveProfiles("prod"); // 強制激活生產(chǎn)環(huán)境配置
        
        // 添加自定義配置源
        Map<String, Object> customProps = new HashMap<>();
        customProps.put("app.name", "my-awesome-app");
        customProps.put("app.version", "1.0.0");
        env.getPropertySources().addFirst(new MapPropertySource("customProps", customProps));
        
        log.info("自定義上下文初始化完成,已添加自定義配置");
    }
}

注冊這個初始化器有三種方式:

  • 在spring.factories中配置:
org.springframework.context.ApplicationContextInitializer=com.example.CustomContextInitializer
  • 在 SpringApplication 中添加:
public static void main(String[] args) {
    SpringApplication app = new SpringApplication(MyApp.class);
    app.addInitializers(new CustomContextInitializer());
    app.run(args);
}
  • 在 application.properties 中配置:
context.initializer.classes=com.example.CustomContextInitializer

典型用途:

  • 多環(huán)境動態(tài)配置切換
  • 從外部服務(wù)獲取配置信息
  • 注冊加密配置解碼器
  • 容器啟動前的檢查工作

執(zhí)行時機揭秘:這個擴展點在 Spring Boot 啟動流程中位于prepareContext階段,早于BeanDefinition的加載,所以不能在這里獲取 Bean,只能做一些環(huán)境配置相關(guān)的工作。

6. Bean 后置處理器:BeanPostProcessor 定制 Bean 的 "成長過程"

如果說 Spring 容器是個 "育兒園",那么BeanPostProcessor就是最敬業(yè)的 "育兒師"—— 它能在 Bean 初始化前后做一些加工處理。不管是給 Bean 添加屬性,還是替換 Bean 實例,甚至是給 Bean 做代理增強,它都能搞定。

這個接口有兩個核心方法:

@Component
publicclass LogBeanPostProcessor implements BeanPostProcessor {

    // Bean初始化方法調(diào)用前執(zhí)行
    @Override
    publicObject postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 給所有Service接口添加日志標(biāo)記
        if (bean.getClass().getName().endsWith("Service")) {
            log.info("Bean初始化前:{}", beanName);
            // 可以在這里給Bean設(shè)置額外屬性
            if (bean instanceof UserService) {
                ((UserService) bean).setLogEnabled(true);
            }
        }
        return bean; // 返回的對象會作為最終的Bean
    }

    // Bean初始化方法調(diào)用后執(zhí)行
    @Override
    publicObject postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 對Controller進行特殊處理
        if (bean.getClass().isAnnotationPresent(Controller.class)) {
            log.info("Bean初始化后:{}", beanName);
            // 這里可以返回代理對象,實現(xiàn)AOP功能
        }
        return bean;
    }
}

神奇用途:

  • 自動為 Bean 注入通用屬性
  • 實現(xiàn) Bean 的動態(tài)代理(Spring AOP 就是這么玩的)
  • 檢查 Bean 是否符合特定規(guī)范
  • 實現(xiàn)自定義注解功能

原理深挖:Spring 內(nèi)部有很多內(nèi)置的BeanPostProcessor,比如:

  • AutowiredAnnotationBeanPostProcessor:處理@Autowired注解的依賴注入
  • AnnotationAwareAspectJAutoProxyCreator:創(chuàng)建 AOP 代理對象
  • InitDestroyAnnotationBeanPostProcessor:處理@PostConstruct和@PreDestroy注解

注意事項:BeanPostProcessor本身也是 Bean,所以不要在它里面依賴其他 Bean,可能會導(dǎo)致循環(huán)依賴或初始化順序問題。如果需要多個后置處理器,可以通過Ordered接口指定順序。

7. Bean 定義后置處理器:BeanFactoryPostProcessor 修改 Bean 藍圖

你知道 Spring 是怎么讀取@Configuration和@Bean注解的嗎?秘密就藏在BeanFactoryPostProcessor里。這個擴展點能讓你在 Bean 實例化之前修改 Bean 的定義信息,比如修改屬性值、添加新的 Bean 定義,甚至替換已有的 Bean 定義。

它就像修改建筑藍圖,在施工前調(diào)整設(shè)計:

@Component
publicclass CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 獲取UserService的Bean定義
        BeanDefinition userServiceDefinition = beanFactory.getBeanDefinition("userService");
        
        // 修改Bean的作用域(從單例改為原型)
        userServiceDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        
        // 添加屬性值
        MutablePropertyValues propertyValues = userServiceDefinition.getPropertyValues();
        propertyValues.add("maxQuerySize", 100);
        
        // 注冊新的Bean定義
        BeanDefinition orderServiceDefinition = new RootBeanDefinition(OrderService.class);
        beanFactory.registerBeanDefinition("orderService", orderServiceDefinition);
        
        log.info("BeanFactoryPostProcessor處理完成,已修改UserService定義");
    }
}

高級玩法:

  • 動態(tài)修改 Bean 的屬性配置,實現(xiàn)多環(huán)境適配
  • 根據(jù)條件注冊不同的 Bean 實現(xiàn)類
  • 批量設(shè)置 Bean 的屬性,比如給所有數(shù)據(jù)源 Bean 設(shè)置連接超時時間
  • 實現(xiàn)自定義注解驅(qū)動的 Bean 配置

MyBatis 的MapperScannerConfigurer就是用這個擴展點實現(xiàn)的,它會掃描指定包下的接口,自動創(chuàng)建 Mapper 接口的 Bean 定義。

執(zhí)行時機:BeanFactoryPostProcessor在 Bean 定義加載完成后,Bean 實例化之前執(zhí)行。和BeanPostProcessor的區(qū)別是:前者處理 Bean 定義,后者處理 Bean 實例。

8. 自定義導(dǎo)入:@Import 與 ImportSelector 動態(tài)裝配 Bean

當(dāng)你的項目越來越大,配置類越來越多,是不是覺得管理起來很麻煩?@Import注解能幫你簡化配置,它可以直接導(dǎo)入普通類、配置類,甚至通過ImportSelector動態(tài)選擇要導(dǎo)入的類。

這就像點餐時的 "套餐" 功能,一鍵導(dǎo)入多個相關(guān)配置:

// 1. 導(dǎo)入普通類(會自動注冊為Bean)
@Import(UserUtil.class)
@Configuration
publicclass AppConfig {
    // UserUtil會被自動注冊到容器中
}

// 2. 導(dǎo)入配置類
@Import({DataSourceConfig.class, MyBatisConfig.class})
@Configuration
publicclass AppConfig {
    // 相當(dāng)于同時加載了DataSourceConfig和MyBatisConfig
}

// 3. 通過ImportSelector動態(tài)導(dǎo)入
publicclass LogImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 根據(jù)條件動態(tài)決定導(dǎo)入哪些類
        boolean enableLog = ClassUtils.isPresent("org.slf4j.Logger", getClass().getClassLoader());
        if (enableLog) {
            returnnew String[]{LogService.class.getName(), LogAspect.class.getName()};
        } else {
            returnnew String[]{DefaultLogService.class.getName()};
        }
    }
}

// 使用自定義ImportSelector
@Import(LogImportSelector.class)
@Configuration
publicclass AppConfig {
    // 會根據(jù)是否有SLF4J依賴導(dǎo)入不同的日志組件
}

實際應(yīng)用:

  • Spring Boot 的自動配置就是通過@Import + ImportSelector實現(xiàn)的
  • 根據(jù)環(huán)境動態(tài)選擇不同的 Bean 實現(xiàn)
  • 模塊化管理配置,按需導(dǎo)入
  • 實現(xiàn)類似@EnableXXX的注解(如@EnableCaching、@EnableAsync)

Spring Cloud 的@EnableEurekaClient就是個典型例子,它通過ImportSelector導(dǎo)入了 Eureka 客戶端的相關(guān)配置類,讓你一行代碼就能開啟服務(wù)注冊發(fā)現(xiàn)功能。

9. 工廠 Bean:FactoryBean 創(chuàng)建復(fù)雜對象的 "專屬工廠"

有些對象創(chuàng)建過程特別復(fù)雜,比如數(shù)據(jù)源、線程池、HttpClient 這些,需要設(shè)置一大堆參數(shù)。如果用普通的@Bean方法配置,代碼會非常臃腫。這時候FactoryBean就能幫你封裝復(fù)雜對象的創(chuàng)建過程,讓配置類保持清爽。

// 自定義FactoryBean創(chuàng)建HttpClient
publicclass HttpClientFactoryBean implements FactoryBean<CloseableHttpClient> {
    privateint connectTimeout = 5000;
    privateint socketTimeout = 30000;
    privateint maxConnections = 100;

    // 設(shè)置屬性的setter方法
    public void setConnectTimeout(int connectTimeout) { this.connectTimeout = connectTimeout; }
    public void setSocketTimeout(int socketTimeout) { this.socketTimeout = socketTimeout; }
    public void setMaxConnections(int maxConnections) { this.maxConnections = maxConnections; }

    // 創(chuàng)建對象的核心方法
    @Override
    public CloseableHttpClient getObject() throws Exception {
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(maxConnections);
        
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build();
                
        return HttpClientBuilder.create()
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .build();
    }

    // 返回對象類型
    @Override
    public Class<?> getObjectType() {
        return CloseableHttpClient.class;
    }

    // 是否單例
    @Override
    public boolean isSingleton() {
        returntrue;
    }
}

// 在配置類中使用
@Configuration
publicclass HttpClientConfig {
    @Bean
    public HttpClientFactoryBean httpClient() {
        HttpClientFactoryBean factoryBean = new HttpClientFactoryBean();
        factoryBean.setConnectTimeout(3000);
        factoryBean.setSocketTimeout(20000);
        factoryBean.setMaxConnections(50);
        return factoryBean;
    }
}

當(dāng)你從容器中獲取httpClient Bean 時,Spring 會自動調(diào)用FactoryBean的getObject()方法返回實際的CloseableHttpClient對象。如果你想獲取FactoryBean本身,可以在 Bean 名稱前加&符號,比如applicationContext.getBean("&httpClient")。

常見應(yīng)用:

  • MyBatis 的MapperFactoryBean用于創(chuàng)建 Mapper 接口的代理對象
  • Spring Data JPA 的JpaRepositoryFactoryBean
  • 各種連接池、客戶端的創(chuàng)建封裝

優(yōu)點:

  • 封裝復(fù)雜對象的創(chuàng)建邏輯,分離關(guān)注點
  • 支持懶加載,只有當(dāng)真正需要對象時才會創(chuàng)建
  • 可以更精細地控制對象的創(chuàng)建過程

10. AOP 切面:Advisor 實現(xiàn)無侵入的功能增強

最后一個必須是 Spring 的王牌功能 ——AOP(面向切面編程)。通過Advisor擴展點,你可以在不修改原有代碼的情況下給方法添加額外功能,比如日志記錄、性能監(jiān)控、事務(wù)控制等。

這就像給手機貼鋼化膜,不改變手機本身,卻能提供額外保護:

// 1. 定義切面邏輯
publicclass LogAdvice implements MethodInterceptor {
    privatestaticfinal Logger log = LoggerFactory.getLogger(LogAdvice.class);

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // 方法執(zhí)行前
        long startTime = System.currentTimeMillis();
        log.info("方法開始:{},參數(shù):{}", 
                invocation.getMethod().getName(), 
                Arrays.toString(invocation.getArguments()));
        
        try {
            // 執(zhí)行目標(biāo)方法
            Object result = invocation.proceed();
            // 方法執(zhí)行后
            log.info("方法結(jié)束:{},返回值:{}", 
                    invocation.getMethod().getName(), 
                    result);
            return result;
        } catch (Exception e) {
            // 異常處理
            log.error("方法異常:{},錯誤:{}", 
                    invocation.getMethod().getName(), 
                    e.getMessage(), e);
            throw e;
        } finally {
            // 計算耗時
            long cost = System.currentTimeMillis() - startTime;
            log.info("方法耗時:{}ms", cost);
        }
    }
}

// 2. 配置Advisor
@Configuration
publicclass AopConfig {
    @Bean
    public LogAdvice logAdvice() {
        returnnew LogAdvice();
    }

    @Bean
    public Advisor logAdvisor() {
        // 定義切點:匹配所有Service中的方法
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* com.example.service..*(..))");
        
        // 創(chuàng)建Advisor,將切點和通知關(guān)聯(lián)
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(logAdvice());
        return advisor;
    }
}

這段代碼會自動給所有 Service 類的方法添加完整的日志記錄,包括:

  • 方法調(diào)用前記錄方法名和參數(shù)
  • 方法執(zhí)行后記錄返回值
  • 方法異常時記錄錯誤信息
  • 統(tǒng)計方法執(zhí)行耗時

AOP 能做的遠不止日志:

  • 事務(wù)管理:@Transactional注解就是通過 AOP 實現(xiàn)的
  • 權(quán)限控制:方法執(zhí)行前檢查權(quán)限
  • 緩存控制:自動實現(xiàn)方法結(jié)果緩存
  • 性能監(jiān)控:統(tǒng)計方法執(zhí)行時間
  • 異常重試:方法失敗時自動重試

Spring 的聲明式事務(wù)就是最經(jīng)典的 AOP 應(yīng)用,通過@Transactional注解,你不需要手動編寫beginTransaction、commit、rollback等代碼,AOP 會在后臺自動幫你完成這些操作。

總結(jié):讓 Spring 為你打工,而不是你為 Spring 打工

掌握這些擴展點后,你會發(fā)現(xiàn) Spring 框架變得無比靈活。不再是你被動適應(yīng)框架,而是框架主動配合你的需求。這 10 個擴展點就像 10 把瑞士軍刀,能幫你輕松解決開發(fā)中的各種復(fù)雜問題:

擴展點

核心作用

最佳實踐

@RestControllerAdvice

全局異常處理

統(tǒng)一 API 響應(yīng)格式

HandlerInterceptor

請求攔截

日志、權(quán)限、性能監(jiān)控

ApplicationContextAware

獲取容器對象

非 Spring 類中使用 Bean

CommandLineRunner

啟動初始化

緩存預(yù)熱、服務(wù)注冊

ApplicationContextInitializer

上下文初始化

環(huán)境配置、配置源注冊

BeanPostProcessor

Bean 加工

屬性注入、代理增強

BeanFactoryPostProcessor

修改 Bean 定義

動態(tài)配置調(diào)整

@Import + ImportSelector

動態(tài)導(dǎo)入配置

模塊化配置、條件裝配

FactoryBean

復(fù)雜對象創(chuàng)建

數(shù)據(jù)源、客戶端創(chuàng)建

Advisor

AOP 增強

日志、事務(wù)、權(quán)限

最好的程序員不是寫最多代碼的人,而是最會利用工具的人。Spring 已經(jīng)為我們提供了這么強大的擴展能力,充分利用這些擴展點,讓你的代碼更簡潔、更靈活、更易于維護。

收藏這篇文章,下次遇到類似問題時翻出來看看,你會發(fā)現(xiàn)曾經(jīng)頭疼的問題,用對擴展點就能輕松解決。覺得有用的話別忘了轉(zhuǎn)發(fā)給你的同事,一起提升開發(fā)效率!

責(zé)任編輯:武曉燕 來源: 石杉的架構(gòu)筆記
相關(guān)推薦

2025-10-27 01:55:00

Jupyter連接器nbconvert

2025-01-20 00:06:13

2025-06-30 02:44:00

SpringBoot開發(fā)優(yōu)化

2023-12-23 11:15:25

2021-10-18 08:01:44

TS語言TypeScript

2025-05-13 09:31:27

2025-09-01 04:00:15

VSCode插件Github

2025-04-28 10:16:35

VSCode插件開發(fā)

2025-07-09 09:32:21

2019-07-11 14:45:52

簡歷編程項目

2025-07-28 06:49:48

Python開發(fā)圖像處理

2024-12-31 00:00:00

VS Code插件工具開發(fā)者

2025-09-01 01:25:00

SpringMVC注解

2024-04-16 00:00:00

Spring微服務(wù)架構(gòu)

2025-07-11 01:05:41

2023-10-27 18:11:42

插件Postman代碼

2024-12-10 07:15:00

2024-09-09 18:18:45

2023-09-21 22:56:32

插件開發(fā)

2024-05-28 14:36:00

Python開發(fā)
點贊
收藏

51CTO技術(shù)棧公眾號