代码源码地址:https://github.com/wujiachengSH/springBeanDemo

概述:本章将讲解Spring对于Bean的管理方案。

目录:

  1. 准备工作
  2. 自动装配
  3. 处理装配歧义性
  4. bean的作用域
  5. 注入式声明Bean

代码环境:

  1. Sts
  2. jdk1.8
  3. spring4

1.准备工作

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

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

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

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

package com.wjc.spring.bean;

public interface Bird {

    void fly();
void feed();
void twitter();
void changeTwiter();
}

2.自动装配

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

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

package com.wjc.spring.bean.impl;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component; import com.wjc.spring.bean.Bird;
//这是知更鸟
@Component
public class Robin implements Bird { private String flyStr ="知更鸟起飞";
private String feedStr = "不想吃东西";
private String twiterStr = "啊啊啊"; @Override
public void fly() {
System.out.println(flyStr);
}
@Override
public void feed() {
System.out.println(feedStr);
}
@Override
public void twitter() {
System.out.println(twiterStr);
}
@Override
public void changeTwiter() {
} }

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

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

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

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

代码源码地址:https://github.com/wujiachengSH/springBeanDemo

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

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

package com.wjc.spring.bean.impl;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component; import com.wjc.spring.bean.Bird;
//这是鹦鹉
@Component
public class Parrot implements Bird { private String flyStr ="鹦鹉起飞";
private String feedStr = "啥都吃";
private String twiterStr = "说人话"; @Override
public void fly() {
System.out.println(flyStr);
} @Override
public void feed() {
System.out.println(feedStr);
} @Override
public void twitter() {
System.out.println(twiterStr);
} @Override
public void changeTwiter() {
twiterStr = "你好你好";
} }

运行结果如下:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.wjc.spring.test.BeanTest': Unsatisfied dependency expressed through field 'bird'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.wjc.spring.bean.Bird' available: expected single matching bean but found 5: 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")来解决声明问题
@Test
public void BeanTest3() {
// 此时鹦鹉添加了@Primary
parrot.fly();
assertNotNull(parrot);
}

4.Bean的作用域

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

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

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

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

package com.wjc.spring.bean.impl;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import com.wjc.spring.bean.Bird; //这是鹌鹑
//这个使用原型模式
@Component
@Qualifier("Quail")
@Scope("prototype")
public class Quail implements Bird { private String flyStr ="鹌鹑起飞";
private String feedStr = "鹌鹑想吃啥就吃啥";
private String twiterStr = "鹌鹑不知道怎么叫"; @Override
public void fly() {
// TODO Auto-generated method stub
System.out.println(flyStr);
} @Override
public void feed() {
// TODO Auto-generated method stub
System.out.println(feedStr);
} @Override
public void twitter() {
// TODO Auto-generated method stub
System.out.println(twiterStr);
} public void changeTwiter() {
twiterStr = "我大鹌鹑今天就是饿死。。。。";
} }

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

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

运行结果:

鹌鹑不知道怎么叫
我大鹌鹑今天就是饿死。。。。
鹌鹑不知道怎么叫
我大鹌鹑今天就是饿死。。。。

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

我们看一下如下代码

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

运行测试类:

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

运行结果:

鹌鹑不知道怎么叫
我大鹌鹑今天就是饿死。。。。
我大鹌鹑今天就是饿死。。。。
我大鹌鹑今天就是饿死。。。。

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

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

@Service
@Scope("prototype")
public class BirdServiceImpl implements BirdService { @Autowired
@Qualifier("Quail")
private Bird bird; public void ScopTest() {
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)

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

package com.wjc.spring.bean.impl;

import com.wjc.spring.bean.Bird;
//这是杜鹃
public class Cuckoo implements Bird { private String flyStr = "fly" ;
private String feedStr = "feed";
private String twiterStr = "twiter"; public Cuckoo(String flyStr, String feedStr, String twiterStr) {
super();
this.flyStr = flyStr;
this.feedStr = feedStr;
this.twiterStr = twiterStr;
} @Override
public void fly() {
// TODO Auto-generated method stub
System.out.println(flyStr);
} @Override
public void feed() {
// TODO Auto-generated method stub
System.out.println(feedStr);
} @Override
public void twitter() {
// TODO Auto-generated method stub
System.out.println(twiterStr);
} @Override
public void changeTwiter() {
// TODO Auto-generated method stub
twiterStr = "杜鹃";
} }

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

package com.wjc.spring.config;

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

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

使用Test方法来执行一下

package com.wjc.spring.test;

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

执行结果

cuckoo fly
cuckoo feed
cuckoo twiter
fly
feed
twiter

可以看到成功的声明了对象。

本文章为在下在查看SPRING实战一书和工作上发生过的问题结合来完成的。希望各位看官指点错误和不合理的地方。

代码源码地址:https://github.com/wujiachengSH/springBeanDemo

Spring实战拆书--SpringBean的更多相关文章

  1. Spring Bean的生命周期,《Spring 实战》书中的官方说法

    连着两天的面试 ,都问到了 Spring 的Bean的生命周期,其中还包括 昨晚一波阿里的电话面试.这里找到了Spring 实战中的官方说法.希望各位要面试的小伙伴记住,以后有可能,或者是有时间 去看 ...

  2. Spring实战6:利用Spring和JDBC访问数据库

    主要内容 定义Spring的数据访问支持 配置数据库资源 使用Spring提供的JDBC模板 写在前面:经过上一篇文章的学习,我们掌握了如何写web应用的控制器层,不过由于只定义了SpitterRep ...

  3. Spring实战——无需一行xml配置实现自动化注入

    已经想不起来上一次买技术相关的书是什么时候了,一直以来都习惯性的下载一份电子档看看.显然,如果不是基于强烈的需求或强大的动力鞭策下,大部分的书籍也都只是蜻蜓点水,浮光掠影. 就像有位同事说的一样,有些 ...

  4. 《Spring实战》学习笔记-第五章:构建Spring web应用

    之前一直在看<Spring实战>第三版,看到第五章时发现很多东西已经过时被废弃了,于是现在开始读<Spring实战>第四版了,章节安排与之前不同了,里面应用的应该是最新的技术. ...

  5. 【Spring实战】—— 1 入门讲解

    这个系列是学习spring实战的总结,一方面总结书中所写的精髓,另一方面总结一下自己的感想. 基础部分讲解了spring最为熟知的几个功能:依赖注入/控制反转 和 面向切面编程. 这两个就不再多说了, ...

  6. Spring实战(中文4,5版) PDF含源码

    Spring实战 读者评价 看了一半后在做评论,物流速度挺快,正版行货,只是运输过程有点印记,但是想必大家和你关注内容,spring 4必之3更加关注的是使用注解做开发,对于初学者还是很有用,但是不排 ...

  7. spring实战学习笔记(一)spring装配bean

    最近在学习spring boot 发现对某些注解不是很深入的了解.看技术书给出的实例 会很疑惑为什么要用这个注解? 这个注解的作用?有其他相同作用的注解吗?这个注解的运行机制是什么?等等 spring ...

  8. 将Spring实战第5版中Spring HATEOAS部分代码迁移到Spring HATEOAS 1.0

    最近在阅读Spring实战第五版中文版,书中第6章关于Spring HATEOAS部分代码使用的是Spring HATEOAS 0.25的版本,而最新的Spring HATEOAS 1.0对旧版的AP ...

  9. Spring实战第4版PDF下载含源码

    下载链接 扫描右侧公告中二维码,回复[spring实战]即可获取所有链接. 读者评价 看了一半后在做评论,物流速度挺快,正版行货,只是运输过程有点印记,但是想必大家和你关注内容,spring 4必之3 ...

随机推荐

  1. java38

    字符串内存分析 String str = new String("ABCD") 会先在堆中开辟一个空间,然后去常量池(方法区)中寻找是否有该变量,如果有,直接引用常量池中的内容 如 ...

  2. Python Day 13 装饰器

    阅读目录   内容回顾 函数嵌套的定义 global.nonlocal关键字 闭包及闭包的运用场景 开放封闭原则 装饰器 一个函数被多次装饰 ##内容回顾 1.函数对象:函数名 => 存放的是函 ...

  3. 使用kbmmw 的REST 服务实现上传大文件

    我们在使用kbmmw的REST 服务时,经常会下载和上传大文件.例如100M以上的.kbmmw的rest服务中 提供标准的文件下载,上传功能,基本上就是打开文件,发送,接收,没有做特殊处理.这些对于文 ...

  4. 渗透测试的理论部分3——ISSAF的详细描述

    ISSAF即信息系统安全评估框架(Information Systems Security Assessment Framework)是另外一种开放源代码的安全性测试和安全分析框架.为了解决安全评估工 ...

  5. Linux---设备文件名和挂载点

    分区: 1.分区: MBR   GPT 2.格式化  : 为了写入文件系统 3.设备文件名 4.什么是挂载点? 挂载点:使用已经存在的空目录作为挂载点 挂载: 必须分区: / (根分区) swap分区 ...

  6. 使用Python脚本分析你的网站上的SEO元素

    撰稿马尼克斯德芒克 上2019年1月, Sooda internetbureau Python就是自动执行重复性任务,为您的其他搜索引擎优化(SEO)工作留出更多时间.没有多少SEO使用Python来 ...

  7. WindowsPE权威指南 第二章 小工具 PEComp代码的C语言实现

    主程序代码 PEComp.c #include <windows.h> #include <Richedit.h> #include <Commctrl.h> #i ...

  8. vue-cli入门

    这也仅仅是入门而已了☺ 自己也在慢慢学习中,不对的地方希望大佬可以多多指教,请不吝赐教,感激不尽. 这章主要是搭建环境: 1.安装node环境 从官网下载并安装node,傻瓜操作,安装完成之后,命令行 ...

  9. 20155205 郝博雅 Exp7 网络欺诈防范

    20155205 郝博雅 Exp7 网络欺诈防范 一.实践内容 (1)简单应用SET工具建立冒名网站 (1分) (2)ettercap DNS spoof (1分) (3)结合应用两种技术,用DNS ...

  10. C++标准库之string返回值研究

    先说结论(不一定适用所有环境): 1) GCC默认开启了返回值优化(RVO),除非编译时指定“-fno-elide-constructors”: 2) 现代C++编译器一般都支持返回值优化: 3) s ...