前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring实战拆书--SpringBean

Spring实战拆书--SpringBean

作者头像
java架构师
发布2019-03-15 10:31:00
3880
发布2019-03-15 10:31:00
举报
文章被收录于专栏:Java架构师进阶Java架构师进阶

1.准备工作

请在github上下载源码结合文章阅读,效果更佳

在创建了SpringBoot项目后,我们首先需要开启组件扫描,如下代码所示。

@Configuration//扫描指定包目录@ComponentScan(basePackages="com.wjc")public class BeanConfig {}

声明一个测试Bean的接口,全文的主要内容都是通过此接口的实现类完成的

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

packagecom.wjc.spring.bean;publicinterfaceBird{voidfly();voidfeed();voidtwitter();voidchangeTwiter();}

2.自动装配

自动装配是最常见的Bean装配形式。

我们首先写一个Bird接口的实现类来展示自动装配,只需一个“@Component”注解即可完成。

packagecom.wjc.spring.bean.impl;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.stereotype.Component;importcom.wjc.spring.bean.Bird;//这是知更鸟@ComponentpublicclassRobinimplementsBird{privateString flyStr ="知更鸟起飞";privateString feedStr ="不想吃东西";privateString twiterStr ="啊啊啊";@Overridepublicvoidfly(){ System.out.println(flyStr); }@Overridepublicvoidfeed(){ System.out.println(feedStr); }@Overridepublicvoidtwitter(){ System.out.println(twiterStr); }@OverridepublicvoidchangeTwiter(){  }}

在测试时,我们只需要使用“@Autowired”注解,就可以拿到对应的对象了

通过Junit可以测试装配是否完成

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=BeanConfig.class)public class BeanTest {@Autowiredprivate Bird bird;//测试1,查看是否自动装配了知更鸟//此时bean.impl只有robin@Testpublic void BeanTest1() {assertNotNull(bird); }}

3.处理自动装配的歧义性(@Qualifier)

试想如果我有2个Bird接口的实现类,spring在装配时是否会因为不知道具体需要哪个实现类而报错?

此时声明一个“Parrot”,也实现bird接口,运行test方法会如何?

packagecom.wjc.spring.bean.impl;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.stereotype.Component;importcom.wjc.spring.bean.Bird;//这是鹦鹉@ComponentpublicclassParrotimplementsBird{privateString flyStr ="鹦鹉起飞";privateString feedStr ="啥都吃";privateString twiterStr ="说人话";@Overridepublicvoidfly(){ System.out.println(flyStr); }@Overridepublicvoidfeed(){ System.out.println(feedStr); }@Overridepublicvoidtwitter(){ System.out.println(twiterStr); }@OverridepublicvoidchangeTwiter(){ twiterStr ="你好你好"; }}

运行结果如下:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating beanwithname'com.wjc.spring.test.BeanTest': Unsatisfied dependency expressed through field'bird';nestedexceptionisorg.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying beanoftype'com.wjc.spring.bean.Bird'available: expected singlematchingbean but found5: parrot,quail,robin,Cuckoo1,Cuckoo2 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)

可以看到,由于Spring并不知道应该将哪一个实现类注入到bird中,报出了 “UnsatisfiedDependencyException”,我们可以通过注解“@Qualifier("parrot")”来解决此问题

//这是鹦鹉@Component@Qualifier("parrot")public class Parrot implements Bird {

在获取实现类时使用如下方式,即可获取到自己想要的对象实例了

@Autowired@Qualifier("parrot") private Bird parrot;//添加@Qualifier("parrot")来解决声明问题@Testpublic void BeanTest3() {// 此时鹦鹉添加了@Primaryparrot.fly();assertNotNull(parrot); }

4.Bean的作用域

已知Spring默认是单例模式,但在多线程高并发的情况下,单例模式其实未必是最佳选择,如果线程A将Bean赋了值,而此时线程B拿取了被A赋值的对象,并返回了对应的结果,此时是不是会出现B返回了预料之外的结果?

本文简单讨论一下原型模式下Bean的传递,和会发生的问题,具体的各自作用域请百度“spring作用域”

已知Spring作用域如下:singleton / prototype / request / session /global session

我们来看一下如下代码,一个原型模式的对象

packagecom.wjc.spring.bean.impl;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.context.annotation.Scope;importorg.springframework.stereotype.Component;importcom.wjc.spring.bean.Bird;//这是鹌鹑//这个使用原型模式@Component@Qualifier("Quail")@Scope("prototype")publicclassQuailimplementsBird{privateString flyStr ="鹌鹑起飞";privateString feedStr ="鹌鹑想吃啥就吃啥";privateString twiterStr ="鹌鹑不知道怎么叫";@Overridepublicvoidfly(){// TODO Auto-generated method stubSystem.out.println(flyStr); }@Overridepublicvoidfeed(){// TODO Auto-generated method stubSystem.out.println(feedStr); }@Overridepublicvoidtwitter(){// TODO Auto-generated method stubSystem.out.println(twiterStr); }publicvoidchangeTwiter(){ twiterStr ="我大鹌鹑今天就是饿死。。。。"; } }

看下在TEST时他的表现如何:

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=BeanConfig.class)public class BeanTest3 {@Autowired@Qualifier("Quail") private Bird bird;@Autowired@Qualifier("Quail") private Bird bird2;//测试原型模式与单例的区别@Testpublic void BeanTest1() {bird.twitter();bird.changeTwiter();bird.twitter();bird2.twitter();bird2.changeTwiter();bird2.twitter(); }}

运行结果:

鹌鹑不知道怎么叫

我大鹌鹑今天就是饿死。。。。

鹌鹑不知道怎么叫

我大鹌鹑今天就是饿死。。。。

spring确实将此Bean对象变成了原型模式。那么作用域是否就这么简单的完成了?

我们看一下如下代码

@Servicepublic class BirdServiceImpl implements BirdService {@Autowired@Qualifier("Quail") private Bird bird;publicvoidScopTest() {bird.twitter();bird.changeTwiter();bird.twitter(); }}

运行测试类:

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=BeanConfig.class)public class ServiceTest {@Autowiredprivate BirdService birdService;@Autowiredprivate BirdService birdService2;//测试在Service上添加和不添加@Qualifier("Quail")时调用的Bean的区别@Testpublic void ServiceTest2() {birdService.ScopTest();birdService2.ScopTest(); }}

运行结果:

鹌鹑不知道怎么叫

我大鹌鹑今天就是饿死。。。。

我大鹌鹑今天就是饿死。。。。

我大鹌鹑今天就是饿死。。。。

????????原型模式失效了????

为什么会发生这种情况?因为在此场景下,“BirdServiceImpl”是单例模式的,对Bean的操作不可避免的变成了单例的,如果添加如下代码结果就会完全不一样

@Service@Scope("prototype")public class BirdServiceImpl implements BirdService {@Autowired@Qualifier("Quail") private Bird bird;publicvoidScopTest() {bird.twitter();bird.changeTwiter();bird.twitter(); }}

再次运行时:

鹌鹑不知道怎么叫

我大鹌鹑今天就是饿死。。。。

鹌鹑不知道怎么叫

我大鹌鹑今天就是饿死。。。。

假设“ServiceTest”方法为Control层,“BirdServiceImpl”方法为Service层,“Quail”为Bean,在实际应用时,应该考虑Scop注解是否会可以成功生效。

如下为测试后的结果

//当Service上有@Scope("prototype"),Bean上有@Scope("prototype")时 返回不同对象 //当Service上有@Scope("prototype"),Bean上无@Scope("prototype")时 返回相同对象 //当Service上无@Scope("prototype"),Bean上有@Scope("prototype")时 返回相同对象 //当Service上无@Scope("prototype"),Bean上无@Scope("prototype")时 返回相同对象

5.注入式声明Bean

在上述代码中,我都是通过硬编码的形式在输入一些内容的,那么能否通过读取配置文件的方式完成输出内容呢?(实际运用场景:获取数据库连接对象Session)

我们首先定义一个对象,可以看到我没有添加任何注解,因为此对象不需要在这里进行装配!

packagecom.wjc.spring.bean.impl;importcom.wjc.spring.bean.Bird;//这是杜鹃publicclassCuckooimplementsBird{privateString flyStr ="fly";privateString feedStr ="feed";privateString twiterStr ="twiter";publicCuckoo(String flyStr, String feedStr, String twiterStr){super();this.flyStr = flyStr;this.feedStr = feedStr;this.twiterStr = twiterStr; }@Overridepublicvoidfly(){// TODO Auto-generated method stubSystem.out.println(flyStr); }@Overridepublicvoidfeed(){// TODO Auto-generated method stubSystem.out.println(feedStr); }@Overridepublicvoidtwitter(){// TODO Auto-generated method stubSystem.out.println(twiterStr); }@OverridepublicvoidchangeTwiter(){// TODO Auto-generated method stubtwiterStr ="杜鹃"; }}

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

我们将Config改造一下,由他来负责装配对象

packagecom.wjc.spring.config;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.ComponentScan;importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.PropertySource;importorg.springframework.core.env.Environment;importcom.wjc.spring.bean.impl.Cuckoo;@Configuration//扫描指定包目录@ComponentScan(basePackages="com.wjc")@PropertySource("classpath:Cuckoo.properties")publicclassBeanConfig{//开启组件扫描//获取资源@AutowiredprivateEnvironment env;//通过配置文件装配Cuckoo@Bean(name="Cuckoo1")publicCuckoo getbird() {returnnew Cuckoo(env.getProperty("flyStr","fly"), env.getProperty("feedStr","feed"), env.getProperty("twiterStr","twiter"));//return new Cuckoo("fly","feed", "twiter");}@Bean(name="Cuckoo2")publicCuckoo getbird2() {returnnew Cuckoo("fly","feed","twiter");  } }

可以看到我声明了2个"Cuckoo"对象实例,分别叫“Cuckoo1”,“Cuckoo2”

使用Test方法来执行一下

packagecom.wjc.spring.test;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.test.context.ContextConfiguration;importorg.springframework.test.context.junit4.SpringJUnit4ClassRunner;importcom.wjc.spring.bean.impl.Cuckoo;importcom.wjc.spring.config.BeanConfig;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=BeanConfig.class)publicclassBeanTest4{@Autowired@Qualifier("Cuckoo2") private Cuckoo Cuckoo;@Autowired@Qualifier("Cuckoo1") private Cuckoo Cuckoo1;//测试通过配置文件装配Bean@Testpublic void BeanTest1() {Cuckoo1.fly();Cuckoo1.feed();Cuckoo1.twitter();Cuckoo.fly();Cuckoo.feed();Cuckoo.twitter(); } }

执行结果

cuckoo fly

cuckoo feed

cuckoo twiter

fly

feed

twiter

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.03.05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云直播
云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档