解决Spring Boot 多模块注入访问不到jar包中的Bean问题

情景描述

一个聚合项目spring-security-tutorial,其中包括4个module,pom如下所示:

<project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.github.jdkong.security</groupId>
  <artifactId>spring-security-tutorial</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>
  <modules>``
    <module>security-core</module>
    <module>security-app</module>
    <module>security-browser</module>
    <module>security-demo</module>
  </modules>

 <!-- 其他部分省略-->
</project>

在此项目中,子项目security-browser是一个简单的maven项目,打成jar包,供security-demo使用,security-demo项目是一个springboot项目。

问题描述

在security-browser项目中自动注入了一个配置类,如下所示:

/**
 * @author jdkong
 */
@Slf4j
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.formLogin()
        .and()
        .authorizeRequests()
        .anyRequest()
        .authenticated();
  }
}

在security-demo中使用此配置类时,不起作用。

问题分析

导致此类问题的主要原因是,此类不在Spring Boot的组件扫描范围之内。

1. 关于 Spring Boot 自动注入及组件扫描

在平时使用 Spring Boot 时,常常会使用到@Configuration,@Contoller,@Service,@Component等注解,被添加这些注解的类,在 Spring Boot 启动时,会自动被 Spring 容器管理起来。

上面提到了,添加了一些注解的类会在Spring Boot 容器启动时,被加载到Spring 容器中。那么,组件扫描的作用就是:当 Spring Boot 启动时,根据定义的扫描路径,把符合扫描规则的类装配到spring容器中。

2. Spring Boot 中 @ComponentScan

简单的介绍了@ComponentScan的基础作用,这个注解为我们使用提供了一些可自定义配置属性,先来看看@ComponentScan注解源码:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
  // 指定扫描包的位置(同:basePackages 属性),可以是单个路径,也可以是扫描的路径数组
  @AliasFor("basePackages")
  String[] value() default {};
 // 指定扫描包的位置(同:value 属性)
  @AliasFor("value")
  String[] basePackages() default {};
 // 指定具体的扫描的类
  Class<?>[] basePackageClasses() default {};
 // bean的名称的生成器
  Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

  Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

  ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
 // 控制符合组件检测条件的类文件  默认是包扫描下的 **/*.class
  String resourcePattern() default "**/*.class";
  // 是否开启对@Component,@Repository,@Service,@Controller的类进行检测
  boolean useDefaultFilters() default true;
  // 包含的过滤条件
  // 1. FilterType.ANNOTATION:  按照注解过滤
  // 2. FilterType.ASSIGNABLE_TYPE:   按照给定的类型
  // 3. FilterType.ASPECTJ:  使用ASPECTJ表达式
  // 4. FilterType.REGEX:   正则
  // 5. FilterType.CUSTOM:  自定义规则
  ComponentScan.Filter[] includeFilters() default {};
  // 排除的过滤条件,用法和includeFilters一样
  ComponentScan.Filter[] excludeFilters() default {};

  boolean lazyInit() default false;

  @Retention(RetentionPolicy.RUNTIME)
  @Target({})
  public @interface Filter {
    FilterType type() default FilterType.ANNOTATION;
    @AliasFor("classes")
    Class<?>[] value() default {};
    @AliasFor("value")
    Class<?>[] classes() default {};
    String[] pattern() default {};
  }
}

总结一下@ComponentScan的常用方式如下:

通过使用value,basePackages属性来指定扫描范围;

自定扫描路径下边带有@Controller,@Service,@Repository,@Component注解加入Spring容器

通过includeFilters加入扫描路径下没有以上注解的类加入spring容器

通过excludeFilters过滤出不用加入spring容器的类

自定义增加了@Component注解的注解方式

3. Spring Boot 中 @SpringBootApplication

在创建Spring Boot 项目之后,在默认的启动类上会被添加@SpringBootApplication注解,这个注解默认帮我们开启一些自动配置的功能,比如:基于Java的Spring配置,组件扫描,特别是用于启用Spring Boot的自动配置功能。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration          // 允许自动配置
@ComponentScan(
  excludeFilters = {@Filter(       // 定义排除规则
  type = FilterType.CUSTOM,        // 采用自定义的方式
  classes = {TypeExcludeFilter.class}   // 自定义实现逻辑
), @Filter(                 // 同上
  type = FilterType.CUSTOM,
  classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

  // 为 @EnableAutoConfiguration 添加 exclude 规则
  @AliasFor(
    annotation = EnableAutoConfiguration.class,
    attribute = "exclude"
  )
  Class<?>[] exclude() default {};

  // 为 @EnableAutoConfiguration 添加 excludeName 规则
  @AliasFor(
    annotation = EnableAutoConfiguration.class,
    attribute = "excludeName"
  )
  String[] excludeName() default {};

  // 为 @ComponentScan 添加 basePackages 规则
  @AliasFor(
    annotation = ComponentScan.class,
    attribute = "basePackages"
  )
  String[] scanBasePackages() default {};

  // 为 @ComponentScan 添加 basePackageClasses 规则
  @AliasFor(
    annotation = ComponentScan.class,
    attribute = "basePackageClasses"
  )
  Class<?>[] scanBasePackageClasses() default {};
}

从上面的源码部分可以看到,@SpringBootApplication是一个组合注解,也就相当于使用一个@SpringBootApplication可以替代@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan几个注解联合使用。

注:此注释从SpringBoot 1.2开始提供,这意味着如果你运行的是较低的版本,并且如果你需要这些功能,你需要手动添加@Configuration,@CompnentScan和@EnableAutoConfiguration。

那么,可能会有这样的问题,我只是使用了一个@SpringBootApplication注解,但是我如何对@ComponentScan的属性做自定义配置呢?

当然,Spring 团队已经很好的解决了这个问题,在@SpringBootApplication注解类中的属性上添加@AliasFor注解,从而实现通过对@SpringBootApplication中的属性进行自定义,达到对对应的注解的属性的自定义。

比如:

@AliasFor(
  annotation = ComponentScan.class,
  attribute = "basePackages"
)
String[] scanBasePackages() default {};

这段代码就是实现,通过对@SpringBootApplication的属性scanBasePackages,实现对@ComponentScan中的属性basePackages进行自定义。

4. 回答开篇问题

先看看项目结构,项目入口文件在子项目security-demo中,并且入口类所在包位置为:package com.github.jdkong.security。

也就是说,在不做任何配置的情况下,此项目只会扫描当前包路径及其子路径下的文件,并将符合条件的对象注入到容器中管理。

再看看配置文件所在的包路径位置:package com.github.jdkong.browser.config,可见此包路径并不在项目扫描的路径范围之内。

这也就导致了,我们定义的配置类,虽然加了@Configuration也不会对我们的项目起到作用。

可以对项目注解进行稍微修改,制定扫描包的范围,就可以简单的解决这个问题。如下:

@SpringBootApplication(scanBasePackages="com.github.jdkong")
public class SecurityApplication {

  public static void main(String[] args) {
    SpringApplication.run(SecurityApplication.class,args);
  }
}

5. 补充说明:@AliasFor

在Spring注解中,经常会发现很多注解的不同属性起着相同的作用,比如@ComponentScan的value属性和basePackages属性。所以在使用的时候就需要做一些基本的限制,比如value和basePackages的值不能冲突,比如任意设置value或者设置basePackages属性的值,都能够通过另一个属性来获取值等等。为了统一处理这些情况,Spring创建了@AliasFor标签。

以上这篇解决Spring Boot 多模块注入访问不到jar包中的Bean问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 基于Spring boot @Value 注解注入属性值的操作方法

    本文主要介绍Spring @Value 注解注入属性值的使用方法的分析,文章通过示例代码非常详细地介绍,对于每个人的学习或工作都有一定的参考学习价值 在使用spring框架的项目中,@Value是经常使用的注解之一.其功能是将与配置文件中的键对应的值分配给其带注解的属性.在日常使用中,我们常用的功能相对简单.本文使您系统地了解@Value的用法. @Value注入形式 根据注入的内容来源,@ Value属性注入功能可以分为两种:通过配置文件进行属性注入和通过非配置文件进行属性注入. 非配置文件注

  • Springboot实现多线程注入bean的工具类操作

    场景: 使用springboot多线程,线程类无法自动注入需要的bean 解决方法: 通过工具类获取需要的bean 工具类代码: import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springfram

  • 解决SpringBoot2多线程无法注入的问题

    1.情况描述 使用springboot2多线程,线程类无法实现自动注入需要的bean,解决思路,通过工具类获取需要的bean 如下 package com.ps.uzkefu.apps.ctilink.handler; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.ps.uzkefu.apps.callcenter.entity.CallRecord; import com.ps.uzkefu.apps.call

  • java SpringBoot自定义注解,及自定义解析器实现对象自动注入操作

    # java-SpringBoot自定义参数解析器实现对象自动注入 解析器逻辑流程图表 后台解析注解的解析器 首先,我在java后台编写了一个解析器,代码如下 import com.ruoyi.framework.interceptor.annotation.LoginUser; import com.ruoyi.project.WebMoudle.WebUser.domain.WebUser; import com.ruoyi.project.WebMoudle.WebUser.service

  • Springboot实现根据条件切换注入不同实现类的示例代码

    最近有个一需求需要根据外界环境的属性(操作系统 || yml属性 || 其他bean的状态) 来实现启动时注入两套不同的实现类, 实现切换. 实现启动时条件注入分2步: 第一步 使用@Conditional(参数为 True false条件实现类 需要你自己实现)注解 @Conditional(RabbitMqCondition.class) public class RabbitmqSMSMsgServiceImpl extends RabbitmqBasicMsgService { // @

  • 基于SpringBoot构造器注入循环依赖及解决方式

    1. 循环依赖是什么? Bean A 依赖 B,Bean B 依赖 A这种情况下出现循环依赖. Bean A → Bean B → Bean A 更复杂的间接依赖造成的循环依赖如下. Bean A → Bean B → Bean C → Bean D → Bean E → Bean A 2. 循环依赖会产生什么结果? 当Spring正在加载所有Bean时,Spring尝试以能正常创建Bean的顺序去创建Bean. 例如,有如下依赖: Bean A → Bean B → Bean C Spring

  • 解决Spring Boot 多模块注入访问不到jar包中的Bean问题

    情景描述 一个聚合项目spring-security-tutorial,其中包括4个module,pom如下所示: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://mav

  • 解决Spring Boot 正常启动后访问Controller提示404问题

    问题描述 今天重新在搭建Spring Boot项目的时候遇到访问Controller报404错误,之前在搭建的时候没怎么注意这块.新创建项目成功后,作为项目启动类的Application在com.blog.start包下面,然后我写了一个Controller,然后包的路径是com.blog.ty.controller用的@RestController 注解去配置的controller,然后路径也搭好了,但是浏览器一直报404.最后找到原因是Spring Boot只会扫描启动类当前包和以下的包 ,

  • Spring自动扫描无法扫描jar包中bean的解决方法

    发现问题 前几天用eclipse打包了一个jar包,jar包里面是定义的Spring的bean. 然后将jar包放到lib下,设置spring的自动扫描这个jar包中的bean,可谁知根本无法扫描到bean,显示错误就是找不到bean,当时就纳闷儿了,为什么扫描不到,结果搜索之后才发现,用eclipse打包jar包要勾选"Add directory entries"才能被Spring正确扫描到,居然有这个说法,呵呵- 不知道 勾选"Add directory entries&

  • 解决Spring Boot和Feign中使用Java 8时间日期API(LocalDate等)的序列化问题

    LocalDate . LocalTime . LocalDateTime 是Java 8开始提供的时间日期API,主要用来优化Java 8以前对于时间日期的处理操作.然而,我们在使用Spring Boot或使用Spring Cloud Feign的时候,往往会发现使用请求参数或返回结果中有 LocalDate . LocalTime . LocalDateTime 的时候会发生各种问题.本文我们就来说说这种情况下出现的问题,以及如何解决. 问题现象 先来看看症状.比如下面的例子: @Sprin

  • 解决spring boot hibernate 懒加载的问题

    spring boot 是快速构建微服务的新框架. 对于数据访问问题可以直接使用jpa技术,但是在单元测试发现spring jpa存在hibernate懒加载问题. 但是spring-boot没有xml配置文件所以现在网络上好多的解决方案并不能适用在spring boot框架中.在遇到该问题苦苦查询后终于无意中发现了解决方案. Spring application using JPA with Hibernate, lazy-loading issue in unit test 英文不好没有细看

  • Spring Boot深入学习数据访问之Spring Data JPA与Hibernate的应用

    目录 前言 Spring Boot的支持 前言 Hibernate是一个开源的对象关系映射框架,它对JDBC及进行了非常轻量级的对象封装,它将POJO简单的java对象与数据库表建立映射关系,是一个全自动的ORM框架,Hibernate可以自动生成SQL语句自动执行. JPA是官方提出的Java持久化规范,JPA通过注解或XML描述对象一关系表的映射关系,并将内存中的实体对象持久化到数据库 Spring Data JPA通过提供基于JPA的Repository极大的简化了JPA的写法,在几乎不写

  • 详解Maven 搭建spring boot多模块项目(附源码)

    本文介绍了Maven 搭建spring boot多模块项目,分享给大家,具体如下: 备注:所有项目都在idea中创建 1.idea创建maven项目 1-1: 删除src,target目录,只保留pom.xml 1-2: 根目录pom.xml可被子模块继承,因此项目只是demo,未考虑太多性能问题,所以将诸多依赖.都写在根级`pom.xml`,子模块只需继承就可以使用. 1-3: 根级pom.xml文件在附录1 1-4: 依赖模块 mybatis spring-boot相关模块 2.创建子模块(

  • 解决Spring Boot 在localhost域奇怪的404问题(Mac book pro)

    在mac系统中,明明url是对的,浏览器也可以打开,一个简单的代码调用就是404,你有没有遇到过? 情景再现 普通的一个controller,返回一个常量. @GetMapping("/project_metadata/spring-boot") public String getMetadata(){ return "{\"data\":1234}";//这个不重要 } 调用接口的方式: content = new JSONObject(res

  • 解决spring boot 1.5.4 配置多数据源的问题

    spring boot 已经支持多数据源配置了,无需网上好多那些编写什么类的,特别麻烦,看看如下解决方案,官方的,放心! 1.首先定义数据源配置 #=====================multiple database config============================ #ds1 first.datasource.url=jdbc:mysql://localhost/test?characterEncoding=utf8&useSSL=true first.datasou

  • 通过Spring Boot配置动态数据源访问多个数据库的实现代码

    之前写过一篇博客<Spring+Mybatis+Mysql搭建分布式数据库访问框架>描述如何通过Spring+Mybatis配置动态数据源访问多个数据库.但是之前的方案有一些限制(原博客中也描述了):只适用于数据库数量不多且固定的情况.针对数据库动态增加的情况无能为力. 下面讲的方案能支持数据库动态增删,数量不限. 数据库环境准备 下面一Mysql为例,先在本地建3个数据库用于测试.需要说明的是本方案不限数据库数量,支持不同的数据库部署在不同的服务器上.如图所示db_project_001.d

随机推荐