Spring Bean详细讲解

Stella981
• 阅读 1060

什么是Bean?

Spring Bean是被实例的,组装的及被Spring 容器管理的Java对象。

Spring 容器会自动完成@bean对象的实例化

创建应用对象之间的协作关系的行为称为:**装配(wiring)**,这就是依赖注入的本质。

Spring 三种配置方案

1.在XML中进行显示配置
2.使用Java代码进行显示配置
3.隐式的bean发现机制和自动装配
推荐方式: 3>2>1

一、自动化装配bean

1.组件扫描(component scanning):Spring 会自动发现应用上下文中所创建的bean。
2.自动装配(autowiring):Spring自动满足bean之间的依赖。

package com.stalkers;

/**
 * CD唱片接口
 * Created by stalkers on 2016/11/17.
 */
public interface ICompactDisc {
    void play(); } 

package com.stalkers.impl;

import com.stalkers.ICompactDisc;
import org.springframework.stereotype.Component;

/**
 * Jay同名专辑
 * Created by stalkers on 2016/11/17.
 */
@Component public class JayDisc implements ICompactDisc { private String title = "星晴"; public void play() { System.out.println(title + ":一步两步三步四步,望着天上星星..."); } } 

Component注解作用:
表明该类会作为组件类。

不过,组件扫描默认是不开启用的,我们还需要显示配置下Spring,从而命令它去寻找带有@Component注解的类,并为其创建bean。

1.java code开启组件扫描:
其中,如果CompoentScan后面没有参数的话,默认会扫描与配置类相同的包

@Configuration
@ComponentScan
public class CDPlayerConfig { @Bean public ICompactDisc disc() { return new JayDisc(); } } 

2.xml启动组件扫描

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.stalkers.impl"/> </beans>

测试代码

package com.stalkers;

import com.stalkers.config.CDPlayerConfig; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * Created by stalkers on 2016/11/18. */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = CDPlayerConfig.class) public class TestPlay { @Autowired private ICompactDisc jayDisc; @Test public void play() { jayDisc.play(); } } 

在ComponentScan扫描的包中,所有带有@Component注解的类都会创建为bean

为组件扫描的bean命名

Spring应用上下文种所有的bean都会给定一个ID。在前面的例子中,尽管我们没有明确地为JayDisc bean设置ID,但是Spring会默认为JayDisc设置ID为jayDisc,也就是将类名的第一个字母变成小写

如果想为这个bean设置不同的ID,那就将期望的值传递给@Component注解

@Component("zhoujielun")
public class JayDisc implements ICompactDisc { ... }

如果不使用@Component注解的话,则使用Java依赖注入规范(Java Dependency Injection)中所提供的@Named注解bean的ID

需要引入:

   <dependency>
            <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency> 

@Named("zhoujielun")
public class JayDisc implements ICompactDisc { .... }

设置组件扫描的基础包

前面再给CDPlayerConfig类设置@ComponentScan,我们并没有设置任何属性,这个时候默认扫描默认包是:CDPlayerConfig类所在包及其包的子包。

如果是下图这种情况,DisConfig与其这时候就需要设置@ComponentScan的扫描的包

Spring Bean详细讲解

@Configuration
@ComponentScan(basePackages = {"com.stalkers.soundsystem"})
public class DiscConfig { } 

basePackages使用的是复数,则意味着可以设置多个基础包。

但是basePackages后面跟的是String类型,这种类型并不安全。可以使用basePackageClasses有下面这种写法:

@Configuration
@ComponentScan(basePackageClasses = {com.stalkers.soundsystem.JayCompactDisc.class}) public class DiscConfig { }

通过为bean添加注解实现自动装配

如果所有的对象都是独立的,彼此之间没有任何依赖,那么使用组件扫描就能自动化装配bean。

但是实际工作中,很多对象会依赖其他对象完成任务。这时候就需要能够将组件扫描得到的bean和他们依赖装配在一起。这就是自动装配(autowiring)

使用Spring的Autowired

public interface IMediaPlayer {
    void play(); }

@Component
public class CDPlayer implements IMediaPlayer { private ICompactDisc cd; @Autowired public CDPlayer(ICompactDisc cd) { this.cd = cd; } public void play() { System.out.println("cd Play:"); cd.play(); } }

CDPlayer类的构造器上添加了@Autowired注解,表明当Spring创建CDPlayerbean的时候,会通过这个构造器来进行实例化

Autowired的多种方式
1.构造器注解(constructor)

2.属性setter注解

3.field注解

不管使用上面3中的哪个方法,Spring都会满足声明的依赖。假如有且只有一个bean匹配依赖的话,那么这个bean将会被装配进来。

如果使用2,3方式注解,有多个bean的话,则用Qualifier指定。

如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常。为了避免异常的出现,可以使用

@Autowired(required = false)
private IMediaPlayer CDPlayer;

required=false表示如果没有匹配的话,Spring会让bean处于未装配的样子。使用未装配的属性,会出现NullPointerException

总结:
所以在使用开发的时候一般建议使用**Resource(package javax.annotation)**进行注解。但是Resource不支持构造器注解

二、通过Java代码装配Bean

尽管在很多场景下通过组件扫描和自动装配实现Spring的自动化更为推荐,但是有时候行不通。比如引用第三方组件,没办法在它的类上添加@Component及@Autowired。所以就需要JavaConfig或者XML配置

在进行显示配置的时候,JavaConfig是更好的解决方案。

JavaConfig与其他的Java代码又有所区别,在概念上它与应用程序中的业务逻辑和领域代码又有所不同。JavaConfig是配置相关代码,不含任何逻辑代码。通常会将JavaConfig放到单独的包中。

创建JavaConfig类

@Configuration
public class CDPlayerConfig { }

使用@Configuration表明CDPlayerConfig是一个配置类

声明简单的bean

@Bean
public IMediaPlayer cdplayer() { return new VCDPlayer(new JayCompactDisc()); }

@Bean注解会告诉Spring将返回一个对象。

**默认情况下,@Bean的Id与带有@Bean的方法名一样**当然也可以通过@Bean的name属性指定额外的方法名

借助JavaConfig注入

在上面的例子中,初始化个VCDPlayer都需要new一个JayCompactDisc对象。如果其他的对象的也需要JayCompactDisc,所以优化如下:

@Bean
public IMediaPlayer cdplayer() { return new VCDPlayer(disc()); } @Bean public ICompactDisc disc() { return new JayCompactDisc(); }

单独抽出disc()方法,在其方法上加上Bean注解,Spring上加@Bean注解的都是**默认单例模式**,不管disc()被多个方法调用,其disc()都是同一个实例。

当然上面的初始化可以优化如下:

@Bean
public IMediaPlayer cdplayer(ICompactDisc disc) { return new VCDPlayer(disc); }

三、通过XML装配Bean

在xml配置中,创建一个xml文件,并且要以元素为根。

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> </beans>

在使用xml的时候,需要在配置文件顶部声明多个xml模式(XML Schema Definition xsd)文件

对于我们需要配置bean的则在spring-beans模式中。

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="jayCompactDisc" class="com.stalkers.soundsystem.JayCompactDisc"></bean> </beans>

1.借助构造器注入初始化bean

构造器注入的方案:
1.元素

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="jayCompactDisc" class="com.stalkers.soundsystem.JayCompactDisc"></bean> <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer"> <constructor-arg ref="jayCompactDisc"/> </bean> </beans>

2.使用Spring3.0所引入的c-命名空间

使用c-命名空间,需要引入:

xmlns:c="http://www.springframework.org/schema/c"

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="jayCompactDisc" class="com.stalkers.soundsystem.JayCompactDisc"></bean> <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:cd-ref="jayCompactDisc"> </bean> </beans>

解析:c-命名空间的语法:

c:cd-ref="jayCompactDisc"

1.c 代表命名空间前缀

2.cd 代表VCDPlayer类的构造器参数名。当然我们也可以使用参数在整个参数列表的位置 c:_0-ref

 <bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:_0-ref="jayCompactDisc">

使用下划线因为参数不能以数字开头,所以加下划线。

3.-ref 代表注入bean引用

4.jayCompactDisc 要注入的bean的id

注意:

c-命名需要写在标签内,与constructor-arg写法差别很大

将字面量注入到构造器中

上面我们所做的DI通常指的是类型的装配,也就是将对象的引用装配到依赖他们的其他对象中,但是有时候我们传的只是一个字面量值

public class VaeCompactDisc implements ICompactDisc { private String title; public VaeCompactDisc(String title) { this.title = title; } public void play() { System.out.println("大家好,我是Vae,下面这首:" + title + "献给大家的"); } }

<bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:_0-ref="vaeCompactDisc"> </bean> <bean id="vaeCompactDisc" class="com.stalkers.soundsystem.VaeCompactDisc"> <constructor-arg value="浅唱"></constructor-arg> </bean>

c-命名空间的写法

<bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:_0-ref="vaeCompactDisc"> </bean> <bean id="vaeCompactDisc" class="com.stalkers.soundsystem.VaeCompactDisc" c:title="城府"> <!--<constructor-arg value="浅唱"></constructor-arg>--> </bean>

装配集合

public class VaeCompactDisc implements ICompactDisc {
    private String title; private List<String> tracks; public VaeCompactDisc(String title, List<String> tracks) { this.title = title; this.tracks = tracks; } public void play() { System.out.println("大家好,我是Vae,下面这专辑:" + title + "献给大家的"); for (String s : tracks) { System.out.println(s); } } }

Spring配置使用constructor-arg。而c-命名的是无法使用装配集合的功能

<bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" c:_0-ref="vaeCompactDisc"> </bean> <bean id="vaeCompactDisc" class="com.stalkers.soundsystem.VaeCompactDisc"> <constructor-arg name="title" value="自定义"></constructor-arg> <constructor-arg name="tracks"> <list> <value>有何不可</value> <value>多余的解释</value> </list> </constructor-arg> </bean>

2.使用属性Setter方法注入

public class CDPlayer implements IMediaPlayer { private ICompactDisc cd; @Autowired public void setCd(ICompactDisc cd) { this.cd = cd; } public CDPlayer(ICompactDisc cd) { this.cd = cd; } public void play() { System.out.println("cd Play:"); cd.play(); } } 

Spring.xml配置里面

<bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer"> <property name="cd" ref="jayCompactDisc"></property> </bean>

元素为属性的Setter方法所提供的功能与元素为构造器所提供的功能是一样的。

与c-命名空间的类似的作为property的替代方案:p-命名空间。使用p-命名空间需要引入:

xmlns:p="http://www.springframework.org/schema/p"

Spring.xml配置如下

<bean id="cdPlayer" class="com.stalkers.soundsystem.VCDPlayer" p:cd-ref="vaeCompactDisc">

语法解析:

p:cd-ref="vaeCompactDisc"

1.p-:命名空间的前缀

2.cd:属性名称

3.-ref:注入bean引用

4.vaeCompactDisc:所注入的bean的id

将字面量注入到属性中

字面量注入到属性与上面将字面量注入到构造方法中方式一样。只不过标签名改成了property。

装配list也是与上面的构造器的装配list一样。

虽然我们无法使用c-及p-命名空间装配list,但是我们可以使用

<bean id="vaeCompactDisc" class="com.stalkers.soundsystem.VaeCompactDisc" c:title="自定义" c:tracks-ref="songs"> </bean> <util:list id="songs"> <value>有何不可</value> <value>多余的解释</value> </util:list>

Spring util命名空间的中的元素:

元素

描述

util:constant

引用某个类型的public static 域

util:list

创建一个java.util.List类型的bean,其中包含值或引用

util:map

创建一个java.util.Map类型的bean,其中包含值或引用

util:properties

创建一个java.util.Properties类型的bean

util:property-path

引用一个bean的属性

util: set

创建一个java.util.Set类型的bean

四、导入和混合配置

在Spring应用中,我们可以同时使用自动化和显示配置。

如果一个JavaConfig配置太臃肿,我们可以把其进行拆分,然后使用@**Import**将拆分的类进行组合

如果希望在JavaConfig里引用xml配置。则可以使用@**ImportResource**

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这