大家好呀我是秋刀鱼🐟~
最近写项目时遇到了很多关于 Spring 注入 bean 的问题,也是耗费了我很多时间去查找注入失败的原因。因此这篇博客就来总结一下 bean 注入失败的常见情况,希望能对你有所帮助😊
🕍博客主页:秋刀鱼与猫__
💗如果觉得博主写的还不错的话,还请大家关注、三连支持一下博主~
目录
常见问题
SpringBoot项目启动时,会默认自动扫描启动类所在的包以及子包下的Bean。
例如下面的这种情况:
项目希望在
com.training包下放置主函数与服务代码,在com.utils包下放置一些配置与工具类。因为启动类所在的包是:
com.training,所以在com.training包与其子包下的 Bean 会被默认自动扫描加入到 Spring 容器中。而
com.utils包不包含在默认扫描的包之内,就算是将 bean1 对象使用注解尝试注入容器,Spring 也不会扫描到该类,因此这是大部分 bean 注入失败的原因。![]()
解决方法
Spring 默认扫描的是启动类所在的包,为了将
com.utils包加入到扫描中,可以使用@ComponentScan指定额外的扫描包,配置如下:package com.training; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication // 将com.utils 包加入到 Spring 扫描范围中 @ComponentScan(basePackages = {"com.training","com.utils"}) @MapperScan(basePackages = "com.training.dao") public class MusicMainClass { public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(MusicMainClass.class, args); } }需要注意的是:指定
@ComponetScan后默认的扫描位置会发生改变,因此添加新的扫描包后要确保启动类所在的包也能被扫描到!不仅仅可以使用
@ComponentScan进行配置,@SpringBootApplication中的 scanBasePackages 属性指定也能起到同样的作用,配置方式如下:package com.training; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ComponentScan; // 使用 scanBasePackages 属性同样能够实现 @SpringBootApplication(scanBasePackages = {"com.training","com.utils"}) @MapperScan(basePackages = "com.training.dao") public class MusicMainClass { public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(MusicMainClass.class, args); } }
常见问题
多模块架构中 bean 无法注入常见问题与情况一相同,都是忽略了 SpringBoot 默认扫描启动类所在包下的 bean。
例如如下的架构:
因为子模块中包路径为
com.common.*,而启动类所在的包路径为:com.training.*,因此子模块中的 bean 无法被 Spring 自动扫描到。
解决方法
与情况一同理,指定
@ComponentScan或ScanbasePackages属性,这里不过多赘述。
bean名称默认规则
使用 Spring 的注解
@Component、@Repository、@Service、@Controller去把一个类配置为bean时,如果不指定bean的名称,那么 bean 的名称的**默认规则**是:
类名的首字母小写,例如:类名称 UserDao ,那么默认的bean名称 userDao
如果类名前两个(或两个以上)连续的字母都是大写,那么默认的bean名称与类名一样,例如:类名称 MIXDao ,那么默认的bean名称 MIXDao
使用 SpringBoot 的注解
@Bean + @Configuration注入 bean 时,如果不指定 bean 的名称,那么 bean 的名称默认规则是:bean 名称与注入的方法名同名
简述
@Qualifer注解
@Autowired注解能够自动注入同类型的 bean,但如果与该属性同类型的 bean 不止一个存在时,Spring 无法判断具体注入哪个 bean ,@Qualifer注解就能够解决这样的歧义。
@Qualifer能够指定 value 字段指定需要注入 bean 的名称,通过指定名称来指定 Spring 到底应该注入哪一个 bean ,这样就能消除歧义,例如下面的例子:public class Teacher{ @Autowired private Student student; }定义一个对象
Teacher其中包含一个 Student 字段的对象<bean id="teacher" class="com.test.Teacher"/> # 下面有两个相同类型不同 name 的 Student bean <bean id="student1"class="com.test.Student"> <property name="name"value="zhangsan"/> </bean> <bean id="student2"class="com.test.Student"> <property name="name"value="lisi"/> </bean>在 xml 文件中配置上述 bean ,此时如果直接注入 Student 那么程序就会报错,因为
@Autowired注解产生了歧义,因此需要使用@Qualifer注解消除歧义:public class Teacher{ @Qualifer(value = "student1") @Autowired private Student student; }
简述
@Resource注解
@Resource注解默认通过 名称 进行注入,名称可以通过 name 属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
常见问题
知道了 bean 的默认命名规则与指定名称的两个注入注解后,可以试着查看注入的 bean 是否出现歧义,如果出现可以使用
@Qualifer注解进行限定。同时使用上述的两个注解之前,需要确保 IOC 容器中存在指定的 bean ,如果没有相应的 bean 也会出现注入失败的情况!
叨叨两句
这两天在写项目,这个问题也是困扰了我很久很久(十几个小时至少)。
在项目中需要集成 SpringBoot + SpringSecurity 做认证授权处理,确定注入的 bean 能够被 Spring 扫描到,同时在 Controller、Service 层的注入也没有问题,但是在用户授权过滤器
UsernamePasswordAuthenticationFilter中死活就是注入不了 bean。开始查阅了大量的博客资料也根本没有往过滤器这方面来思考,在不断地折磨后最终还是找到了问题的所在。
![]()
常见问题
在 WebMVC 框架中,各个元素的加载是有一定顺序的,这个顺序按照:
- context-param–>listener–>filter–>servlet --> … -> Bean 的实例化
而拦截器是在Spring MVC中配置的,如果从整个项目中看,一个servlet请求的执行过程就变成了这样:
- context-param–>listener–>filter–>servlet–>interceptor(指的是拦截器) --> … -> Bean 的实例化
因此上述元素中注入 bean 时,bean 对象的实例化还没有开始,因此注入的值永远为 null 值!
解决方法
上述对象时,使用实例化的方式配置或是将需要注入的对象注入配置类中,在配置类中使用构造函数实例化对象,例如下面的方式:
使用构造函数:
将需要注入的对象在配置类中注入,并将其传入构造函数参数进行实例化:
众所周知 idea 作为 java 程序员的一大利器,其功能相当的强大,今天也是在苦恼于 bean 注入失败原因时,发现了IDEA支持查看 IOC 容器的功能,有了这一功能以后再遇上 bean 注入失败时就能够更快地找到失败原因了!
使用
- 当启动 SpringBoot 项目后点击下方的 Run 按钮(Debug 启动方式点击 Debug 按钮):
- 点击 Console 栏上方的 Actuator :
进入下面的页面后点击 Beans 与 Application :
可以看到右方出现了 IOC 容器中的所有 bean 数据信息:
有了这一利器就再也不怕 bean 无法注入的问题了!
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
由于fast-stemmer的问题,我很难安装我想要的任何rubygem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r
当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。
首先回顾一下拉格朗日定理的内容:函数f(x)是在闭区间[a,b]上连续、开区间(a,b)上可导的函数,那么至少存在一个,使得:通过这个表达式我们可以知道,f(x)是函数的主体,a和b可以看作是主体函数f(x)中所取的两个值。那么可以有, 也就意味着我们可以用来替换 这种替换可以用在求某些多项式差的极限中。方法: 外层函数f(x)是一致的,并且h(x)和g(x)是等价无穷小。此时,利用拉格朗日定理,将原式替换为 ,再进行求解,往往会省去复合函数求极限的很多麻烦。使用要注意:1.要先找到主体函数f(x),即外层函数必须相同。2.f(x)找到后,复合部分是等价无穷小。3.要满足作差的形式。如果是加
我正在尝试在Rails上安装ruby,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf