Spring中的@Import注解妙用

Spring中的@Import注解

介绍

@Import注解更多是用在写公共模块、自动装配的时候用到,比如说公共模块有请求日志记录、限流、加密等等功能,这些功能打包后都在一个jar中,而在一些项目中,只需要启动公共模块中的某些功能,比如只需要启用日志记录等,不用把所有功能都加载,这时候就可以用@Import注解,超级方便

记录请求日志案例

1、新建HttpLogHandlerInterceptor.java请求日志打印类,用于记录打印日志

import cn.hutool.core.date.SystemClock;
import com.bingo.study.common.core.utils.IPUtil;
import com.bingo.study.common.core.utils.JsonMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author h-bingo
 * @Date 2023-05-28 14:47
 * @Version 1.0
 */
@ConditionalOnMissingBean(HttpLogHandlerInterceptor.class)
public class HttpLogHandlerInterceptor implements HandlerInterceptor, InitializingBean {

    private static final Logger log = LoggerFactory.getLogger("[ === Request LOG === ]");

    private static final NamedThreadLocal<Long> COST_TIME = new NamedThreadLocal<>("HttpLogHandlerInterceptor");

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        COST_TIME.set(SystemClock.now());
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) throws Exception {
        try {
            Map<Object, Object> paramMap = new HashMap<>();
            // 请求方法
            String method = request.getMethod();
            // 请求路径
            String servletPath = request.getServletPath();
            // ip地址
            String ipAddr = IPUtil.getIpAddr(request);
            // 耗时
            long costTime = SystemClock.now() - COST_TIME.get();

            paramMap.put("method", method);
            paramMap.put("servletPath", servletPath);
            paramMap.put("ip", ipAddr);
            paramMap.put("costTime", costTime + "ms");

            log.info(JsonMapper.getInstance().toJsonString(paramMap));
        } catch (Exception ignored) {
        } finally {
            COST_TIME.remove();
        }
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("请求日志打印已开启");
    }
}

2、新建HttpLogHandlerAutoConfig.java类,配置请求日志打印类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Author h-bingo
 * @Date 2023-05-28 15:27
 * @Version 1.0
 */
@ConditionalOnMissingBean(HttpLogHandlerAutoConfig.class)
@Import({HttpLogHandlerInterceptor.class})
public class HttpLogHandlerAutoConfig implements WebMvcConfigurer {

    @Autowired
    private HttpLogHandlerInterceptor httpLogHandlerInterceptor;

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

3、以上基本功能就都已经完成了,可以发现并没有使用常见的@Bean或者@Component等spring注解,在HttpLogHandlerInterceptor类上只有@ConditionalOnMissingBean(HttpLogHandlerInterceptor.class)注解,这个注解的意思是Spring容器中不存在HttpLogHandlerInterceptor类的bean才注入(并没有注入bean的功能,只是一个条件限制)。

4、那么如何使用这个功能呢?新建EnableHttpLogInterceptor.java注解,在这个注解上标注@Import({HttpLogHandlerAutoConfig.class})

import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

/**
 * @Author h-bingo
 * @Date 2023-05-28 15:24
 * @Version 1.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({HttpLogHandlerAutoConfig.class})
public @interface EnableHttpLogInterceptor {
}

5、在项目的启动类上加上@EnableHttpLogInterceptor注解,然后随便新建一个controller接口,启动项目访问接口看效果,如下
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

6、可以看到项目启动后,HttpLogHandlerInterceptor类中日志‘请求日志打印功能已开启’成功打印,并且访问接口后有相应的日志记录,说明配置成功

原理分析

在以上案例中,首先是在启动类上标注了@EnableHttpLogInterceptor注解,项目启动后会加载这个注解,然后通过这个注解找到@Import({HttpLogHandlerAutoConfig.class}),此时将HttpLogHandlerAutoConfig.class类注入到spring容器中,然后又通过@Import({HttpLogHandlerInterceptor.class})将HttpLogHandlerInterceptor.class注入到容器中,因此在启动的过程中可以看到HttpLogHandlerInterceptor.class类中的afterPropertiesSet方法打印的日志

@Import源码分析

找到ConfigurationClassParser.java类processImports()方法,先看ge tImports()
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上图分别是收集import进来的类,StudySystemApplication(启动类)、HttpLogHandlerAutoConfig(配置类)、HttpLogHandlerInterceptor(功能实现类)
在这里插入图片描述
往下直接看箭头处,前面两个if是另外两种用法
在这里插入图片描述

结束语

好了,本次分享Spring中的@Import注解简单使用就结束了,欢迎大家指正。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tiny丶bingo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值