栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

springboot中间件小demo

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

springboot中间件小demo

在我们开发的时候,如果用到一个功能,我们只需要导入starter依赖,就能够利用springboot的自动装配功能,使用starter包中的功能了.对应的我们也能自己实现一个starter来使用.
越是使用简单的框架越是有很多的约定,俗称:约定大于配置;

自动装配原理

1、springboot在启动的时候会去starter的包中寻找resources/META-INF/spring.factories文件,并读取文件中 key=org.springframework.boot.autoconfigure.EnableAutoConfiguration的所有value的AutoConfigure类进行加载.
2、在加载AutoConfigure的时候,会有一系列的@Conditional注解,满足条件就会自动配置,并把Bean注入到Spring容器中.也可以通过@ImportAutoConfiguration指定自动装配的类
3、Spring官方的starter一般采取spring-boot-starter-{name}的命名方式,比如spring-boot-starter-aop.非官方的starter,官方的建议artifactId命名应该遵循{name}-spring-boot-starter的格式.

项目结构

依赖


    4.0.0

    org.itpluto.demo
    list-spring-boot-starter
    1.0-SNAPSHOT
    
        org.springframework.boot
        spring-boot-starter-parent
        2.6.7
    

    
        8
        8
    

    
        
        
            org.springframework.boot
            spring-boot-starter-aop
        
        
            commons-beanutils
            commons-beanutils
            1.7.0
        
        
            org.apache.commons
            commons-lang3
        
        
            commons-collections
            commons-collections
            3.2.1
        
        
            com.alibaba
            fastjson
            1.2.47
        
        
            org.projectlombok
            lombok
        
    
    
        
            
                org.apache.maven.plugins
                maven-jar-plugin
                2.3.2
                
                    
                        false
                        true
                        
                            true
                            true
                        
                        
                            ${maven.build.timestamp}
                        
                    
                
            
        
    

自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DoList {
    String key() default "";
    String returnJson() default "";
}
自动装配需要的类和配置文件

1、在resources文件下创建一个META-INF文件夹,并创建spring.factories文件.

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
  org.itpluto.demo.config.StarterAutoConfigure

2、创建StarterAutoConfigure类

@Configuration
@ConditionalOnClass(StarterService.class)
@EnableConfigurationProperties(StarterServiceProperties.class)
public class StarterAutoConfigure {
    
    // StarterServiceProperties 用来读取配置文件中
    @Autowired
    private StarterServiceProperties properties;

    // 把读取到的白名单存储在 StarterService里
    @Bean
    @ConditionalOnMissingBean //当没有这个Bean的时候才会创建
    // 当有以itpluto开头的配置,并且enabled的属性是ture的时候才生效
    @ConditionalOnProperty(prefix = "itpluto.door", value = "enabled", havingValue = "true")
    StarterService starterService() {
        return new StarterService(properties.getUserStr());
    }

    // doJoinPoint aop拦截,这里注册到Spring容器中
    @Bean
    @ConditionalOnMissingBean
    DoJoinPoint doJoinPoint(){
        return new DoJoinPoint();
    }
}

3、创建Properties类,用来yaml配置文件和属性进行绑定

@ConfigurationProperties("itpluto.door")
public class StarterServiceProperties {

    private String userStr;

    public String getUserStr() {
        return userStr;
    }

    public void setUserStr(String userStr) {
        this.userStr = userStr;
    }
}

4、创建StarterService类,用来存储配置文件配置的白名单,以及做进一步的处理

// 自动装配该service
public class StarterService {
	// 把读取到的白名单存储到userStr中
    private String userStr;

    public StarterService(String userStr) {
        this.userStr = userStr;
    }

    public String[] split(String separate){
        return this.userStr.split(separate);
    }
}

5、创建DoJoinPoint类

@Aspect
public class DoJoinPoint {

    private Logger logger = LoggerFactory.getLogger(DoJoinPoint.class);

    @Autowired
    private StarterService starterService;

    @Pointcut("@annotation(org.itpluto.demo.annotation.DoList)")
    public void aopPoint() {
    }

    @Around("aopPoint()")
    public Object doRouter(ProceedingJoinPoint jp) throws Throwable {
        //获取内容
        Method method = getMethod(jp);
        DoList door = method.getAnnotation(DoList.class);
        //获取字段值
        String keyValue = getFiledValue(door.key(), jp.getArgs());
        logger.info("itpluto list handler method:{} value:{}", method.getName(), keyValue);
        if (null == keyValue || "".equals(keyValue)) return jp.proceed();
        //配置内容
        String[] split = starterService.split(",");
        //白名单过滤
        for (String str : split) {
            if (keyValue.equals(str)) {
                return jp.proceed();
            }
        }
        //拦截
        return returnObject(door, method);
    }

    private Method getMethod(JoinPoint jp) throws NoSuchMethodException {
        Signature sig = jp.getSignature();
        MethodSignature methodSignature = (MethodSignature) sig;
        return getClass(jp).getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
    }

    private Class getClass(JoinPoint jp) throws NoSuchMethodException {
        return jp.getTarget().getClass();
    }

    //返回对象
    private Object returnObject(DoList doGate, Method method) throws IllegalAccessException, InstantiationException {
        Class returnType = method.getReturnType();
        String returnJson = doGate.returnJson();
        if ("".equals(returnJson)) {
            return returnType.newInstance();
        }
        // 注意因为这里底层用的是构造器来转换的,
        // 所以需要把code和info也加到构造器中,否则转换不成功
        return JSON.parseObject(returnJson, returnType);
    }

    //获取属性值
    private String getFiledValue(String filed, Object[] args) {
        String filedValue = null;
        for (Object arg : args) {
            try {
                if (null == filedValue || "".equals(filedValue)) {
                    filedValue = BeanUtils.getProperty(arg, filed);
                } else {
                    break;
                }
            } catch (Exception e) {
                if (args.length == 1) {
                    return args[0].toString();
                }
            }
        }
        return filedValue;
    }
}

上面中间件就到此为止了,下面演示一下他的用法.
创建一个使用案例:itpluto-demo-springboot-helloworld

项目结构

依赖


    4.0.0

    org.itpluto.demo
    itpluto-demo-springboot-helloworld
    1.0-SNAPSHOT

    
        org.springframework.boot
        spring-boot-starter-parent
        2.6.7
    

    
        8
        8
    

    
        
        
            org.itpluto.demo
            list-spring-boot-starter
            1.0-SNAPSHOT
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            com.fasterxml.jackson.core
            jackson-annotations
            2.13.0
        
        
            com.fasterxml.jackson.core
            jackson-core
            2.13.0
        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.13.0
        
        
            org.projectlombok
            lombok
        
    

配置文件
server:
  port: 8080
  
# 自定义中间件配置
itpluto:
  door:
    enabled: true
    userStr: 1001,aaaa,ccc #白名单用户ID,多个逗号隔开
实体类
@Data
public class UserInfo {

    private String code;

    private String info;

    private String name;

    private Integer age;

    private String address;

    public UserInfo(String code,String info,String name, Integer age, String address) {
        this.code = code;
        this.info = info;
        this.name = name;
        this.age = age;
        this.address = address;
    }
}
Controller类
@RestController
@RequestMapping("/base")
public class HelloWorldController {

    @DoList(key = "userId", returnJson = "{"code":"403","info":"不在白名单内,没有权限!"}")
    @GetMapping("/api/queryUserInfo")
    public UserInfo queryUserInfo(@RequestParam String userId) {
        return new UserInfo("200","success","火锅:" + userId, 1, "上海市宝山区宝安公路");
    }
}
启功类
@SpringBootApplication
public class HelloWorldApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(HelloWorldApplication.class, args);
        // 测试一下启动的时候,中间件中的doJoinPoint是否注入到Spring容器
        Object doJoinPoint = run.getBean("doJoinPoint");
        System.out.println("doJoinPoint = " + doJoinPoint);
    }
}
测试结果

1、注入成功!

2、白名单

3、黑名单

注意:在引用中间件的时候,因为只是在我们的本地,所以需要先install到我们的本地仓库,不然会找不到这个包,每次修改中间件的内容记得要clean install,这样使用方使用的才是最新的.
这是我从一个大佬的博客里面学习的小demo,他的demo不是全的,我自己按照他的demo写了一遍.有不妥的地方请指教.大佬博客地址

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/850291.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号