Spring IoC与bean

A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application.

bean是由Spring IoC容器实例化、装配和管理的对象,否则,bean只是应用程序中的众多对象之一。

bean及其之间的依赖关系反映在容器使用的配置元数据中。

我们已经了解,Spring IoC容器能够帮我们操作bean,但是前提是我们需要配置元数据以告知Spring容器,它才能够通过读取这些配置,来实例化,装配和管理bean对象。

而配置元数据的方式,就是我们今天要总结的三种,分别是XML,Java注解以及Java代码。我们通过这几种方式,向Spring容器传达这些对象之间丰富的相互依赖关系。

该图是Spring如何工作的高级视图。可以看到,应用程序类与配置元数据相结合,在创建并初始化ApplicationContext之后,就可以获得一个完全配置和可执行的系统或应用程序。

基于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">
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>

id属性表示bean的唯一标识。

class属性定义bean的类型并使用完全限定的类名。

bean实例的三种创建方式

<!-- 一、使用默认构造函数创建,如果没有该默认构造函数,则创建失败。 -->
<bean id="userService" class="com.smday.service.impl.UserServiceImpl"></bean> <!-- 二、使用普通公章中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器 -->
<bean id="instanceFactory" class="com.smday.factory.InstanceFactory"></bean>
<bean id="userService" factory-bean="instanceFactory" factory-method="getUserService"></bean>
<!-- 三、使用工厂中的静态方法创建对象 -->
<bean id="userService" class="com.smday.factory.StaticFactory" factory-method="getUserService"></bean>

依赖注入的两种方式

构造器注入方式

<bean>标签的内部定义<constructor-arg>标签。

public class ExampleBean {

    private AnotherBean beanOne;

    private YetAnotherBean beanTwo;

    private int i;

    public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
<bean id="exampleBean" class="examples.ExampleBean">
<!-- constructor injection using the nested ref element -->
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg> <!-- constructor injection using the neater ref attribute -->
<constructor-arg ref="yetAnotherBean"/> <constructor-arg type="int" value="1"/>
</bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

value:用于提供基本类型和String类型的数据。

ref:用于提供其他的bean类型数据,在spring的ioc核心容器中出现过的bean对象。

在创建对象时,如果没有提供构造器中的这些参数,将无法创建该对象。

setter方法注入方式

<bean>标签的内部定义<property>标签。

public class ExampleBean {

    private AnotherBean beanOne;

    private YetAnotherBean beanTwo;

    private int i;

    public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
} public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
} public void setIntegerProperty(int i) {
this.i = i;
}
}
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested ref element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property> <!-- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

name:指定注入时调用的set方法的属性名称。

value:提供基本类型和String类型的数据。

ref:提供其他的bean类型数据,在spring的ioc核心容器中出现过的bean对象。

如果某个成员必须有值,但并没有提供相应的setter方法,将会出错。

【集合类型的注入】:分为list和map两类结构

    <bean id="userService" class="com.smday.service.impl.UserServiceImpl">
<property name="myStrs">
<array>
<value>AAA</value>
<value>BBB</value>
<value>BBB</value>
</array>
</property>
<property name="myList">
<list>
<value>AAA</value>
<value>BBB</value>
<value>BBB</value>
</list>
</property>
<property name="mySet">
<set>
<value>AAA</value>
<value>BBB</value>
<value>BBB</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="testA" value="AAA"></entry>
<entry key="testB" >
<value>BBB</value>
</entry>
</map>
</property>
<property name="myProp">
<props>
<prop key="testC">CCC</prop>
<prop key="testD">DDD</prop>
</props>
</property>
</bean>

list结构可以使用list、array和set标签。

map结构可以使用map和props标签。

利用命名空间简化xml

一、p-namespace使用bean元素的属性来提供属性值和协作bean,而不是使用嵌套的<property/>元素,下面两段bean的配置效果相同。

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 传统的xml声明 -->
<bean name="classic" class="com.example.ExampleBean">
<property name="email" value="foo@bar.com"/>
</bean>
<!-- p-namespace 声明 -->
<bean name="p-namespace" class="com.example.ExampleBean"
p:email="foo@bar.com"/>
</beans>

二、Spring 3.1中新引入的c-namespace允许使用内联属性来配置构造函数参数,而不是使用嵌套的<constructor-arg>

<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="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/> <!-- 传统的xml声明 -->
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
<constructor-arg value="foo@bar.com"/>
</bean> <!-- c-namespace 声明 -->
<bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/> </beans>

基于Java的显式装配

@Bean 和 @Configuration

这两个注解类是Spring's new java-configuration的核心构件。

@Bean注解用于指示方法实例化、配置和初始化要由Spring IoC容器管理的新对象,@Bean注解的作用与<bean/>标签相同。简单的理解就是这个注解可以告知spring,这个方法上面未来希望注册一个应用上下文的bean对象,因此用@Bean注解的方法需要利用Java代码,定义返回一个bean实例的逻辑。

@Configuration注解一个类表明这个类的主要目的是作为bean定义的源,@Configuration类允许通过简单地调用同一类中的其他@Bean方法来定义bean之间的依赖关系。简单的理解就是一个配置类,自此之后,你可以在该配置类中完成在xml中完成的事,但形式会有所不同。

下面这个例子是一个最简单的配置类的定义:

@Configuration
public class AppConfig { @Bean
public MyService myService() {
return new MyServiceImpl();
}
}

它的作用和下面这段xml配置的方式等价:

<beans>
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>

Bean的依赖

一个@Bean注释的方法可以有任意数量的参数来描述构建该bean所需的依赖关系。例如,如果我们的TransferService需要一个AccountRepository,我们可以通过一个方法参数来实现这个依赖:

@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}

当spring调用transferService方法创建bean时,会自动装配accountRepository到配置方法中,再次印证了那句话,带有@Bean注解的方法可以编写任何必要的Java代码来产生Bean的实例,例如构造器,setter方法,以及任何可以产生实例的方法。

初始化Spring容器

AnnotationConfigApplicationContext是Spring 3.0中新增的。它不仅可以接受@Configuration配置类作为输入,还可以接受普通的@Component类和使用JSR-330元数据注释的类。

初始化spring容器,获取Myservice对象,调用对象的方法。

public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}

定制bean的命名

默认情况下,配置类将会使用@Bean注解的方法的名称作为bean的名称,这一点可以通过name属性修改。

@Configuration
public class AppConfig { @Bean(name = "myFoo")
public Foo foo() {
return new Foo();
}
}

如上:如果没有指定name属性,该bean的名称为foo,如果指定了name属性,这里的名称就是myFoo。

基于注解的自动装配

Spring从以下两个角度实现自动装配:

  • 组件扫描:Spring自动发现应用上下文中所创建的bean。
  • 自动装配:Spring自动满足bean之间的依赖。

首先还是来看一段简单的例子:

//定义一个UserService接口
public interface UserService {
void add();
}
//定义实现类,注意加上@Component注解,告知spring创建这个bean
@Component
public class NormalUserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("添加用户");
}
}
//controller层,注意@Autowired注解,自动按类型注入Userservice
@Component
public class UserController {
@Autowired
private UserService userservice; public void add(){
userservice.add();
}
}
//定义配置类,注意@ComponentScan("com.my.demo")注解开启组件扫描
@Configuration
@ComponentScan("com.my.demo")
public class Appconfig { }
//整合junit测试类进行测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Appconfig.class)
public class UserServiceTest {
@Autowired
private UserService userservice;
@Test
public void testMethod(){
userservice.add();
}
}

以上就是一套可以正常运行的简单案例,当然其中有不少可能出现的问题或者是其他可以实现相同功能的方案,我们都暂且不提。其中出现了许多自动化装配bean的注解,我们一一来看:

自动装配的常用注解

【@Component】

  • 作用:将当前类对象存入spring容器中。
  • 属性:value,用于指定bean的id,不指定value时,默认值为当前类名首字母小写。

值得一提的是,在三层架构中,Spring框架提供了明确的三层注释,作用与@Component相同,但语义更加清晰明了,分别是:

Controller:表现层、Service:业务层、Respository:持久层

【@Autowired】

  • 作用:自动按照类型注入,只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功。
  • 如果ioc容器中没有任何bean类型和要注入的变量类型匹配,则报错(解决方法是,设置required属性的值为false,如果没找到对应类型的bean,则会出于未装配状态),如果ioc容器中有多个类型匹配时,出现歧义性,也会报错。
  • 出现位置:既可以是构造器,也可以是setter方法,甚至任何其他的方法,Spring都会尝试满足方法参数上声明的依赖。
  • 细节:在使用注解注入时,set方法就不是必须的了。

当出现歧义性时,满足类型要求的bean不是唯一时,可以考虑使用@Qualifier和@Resource注解,参考:Spring解决自动装配歧义性的几种方案

【@Configuration】

  • 作用:指定当前类是一个配置类
  • 细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。

【@ComponentScan】

  • 作用:开启组件扫描,用于通过注解指定spring在创建容器时要扫描的包。
  • 属性:value,和basePackages的作用相同,指定创建容器时要扫描的包。
  • 如果不指定value或者basePackages的值,将会默认扫描与配置类相同的包

设置spring组件扫描的基础包的几种方案:

  • @ComponentScan("com.my.demo")

  • @ComponentScan(basePackages = {"com.my.demo.web","com.my.demo.service"})

  • @ComponentScan(basePackageClasses = {UserController.class, UserService.class, UserDao.class}),相较于第二种,较为安全。

需要注意的是,组件扫描默认是不开启的,我们需要通过该注解显式通知Spring,告诉它去寻找带有@Component注解的类,去创建该类的bean对象。

开启组件扫描的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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--配置扫描,相当于@ComponentScan("com.my.demo")-->
<context:component-scan base-package="com.my.demo"/>
</beans>

既然使用xml方式开启组件扫描,那么测试的时候需要谨慎,要读取该xml文件:@ContextConfiguration("classpath:applicationContext.xml")

导入和混合配置

直接以例子呈现:

#jdbcConfig.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=123456
/**
* @author Summerday
* <p>
* 和spring连接数据库相关的配置类
*/
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password; /**
* 创建queryRunner对象
*
* @param dataSource
* @return
*/
@Bean(name = "runner")
@Scope("prototype")
public QueryRunner createQueryRunner(DataSource dataSource) {
return new QueryRunner(dataSource);
} /**
* 创建数据源对象
*
* @return
*/
@Bean(name = "dataSource")
public DataSource createDataSource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

【@Value】

  • 作用:用于基本类型和string类型的数据。
  • 属性:value,指定数据的值,可以使用spring中的SpEL,spring的el表达式。
  • SpEL的写法:${表达式}。
/**
* 主配置类
*/
@Configuration
@ComponentScan(basePackages = "com.smday")
@Import(JdbcConfig.class)
@PropertySource("classpath:JdbcConfig.properties")
public class SpringConfiguration {
}

【@Import】

  • 作用:用于导入其他的配置类。
  • 属性:value,指定其他配置类的字节码,使用Import注解后,有该注解的类为父配置类,导入的都是子配置类。

【@PropertySource】

  • 作用:作用于指定properties文件的位置。
  • 属性:value,指定文件的名称和路径,关键字classpath表示类路径下。

最后的最后,引用Spring in Action中作者的话:自动化配置、基于Java的显式配置以及基于xml的显式配置都描述了Spring应用中组件以及这些组件之间的关系。作者建议尽可能使用自动化的配置,其次如果需要显式配置,希望优先选择基于Java的配置,类型安全且易懂。

Spring装配Bean的三种方式+导入和混合配置的更多相关文章

  1. spring装配bean的三种方式及其混合装配

    在spring容器中装配bean有三种基本方式和混合装配方式: 隐式的bean自动发现机制和自动装配 在java中进行显式配置 在xml中配置 混合装配(在多个java文件中配置.在JavaConfi ...

  2. spring 装配bean的三种方式

    这段时间在学习Spring,依赖注入DI和面向切面编程AOP是Spring框架最核心的部分.这次主要是总结依赖注入的bean的装配方式. 什么是依赖注入呢?也可以称为控制反转,简单的来说,一般完成稍微 ...

  3. spring创建bean的三种方式

    spring创建bean的三种方式: 1通过构造方法创建bean(最常用) 1.1 spring默认会通过无参构造方法来创建bean,如果xml文件是这样配置,则实体类中必须要有无参构造方法,无参构造 ...

  4. Spring容器装配Bean的三种方式

    欢迎查看Java开发之上帝之眼系列教程,如果您正在为Java后端庞大的体系所困扰,如果您正在为各种繁出不穷的技术和各种框架所迷茫,那么本系列文章将带您窥探Java庞大的体系.本系列教程希望您能站在上帝 ...

  5. Spring实战(三)Spring中装配Bean的三种方式---XML、JavaConfig、AutoWire

    创建应用对象之间协作关系的行为称为装配(wiring),这也是依赖注入的本质. Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系,而开发者需要告诉Spring需要创建哪些 ...

  6. 装配Bean的三种方式

    一.装配Bean就是在xml写一个Bean标签:装配完Bean,还需要读取xml配置文件创建Spring容器来创建对象: 1.new 实现类方式 正常的三种创建Bean容器的方法都可以根据装配的Bea ...

  7. Spring 实例化bean的三种方式

    第一种方法:直接配置Bean <bena id="所需要实例化的一个实例名称" class="包名.类名"/> 例如: 配置文件中的bean.XML ...

  8. Spring实例化Bean的三种方式及Bean的类型

    1.使用类构造器实例化  [默认的类构造器] <bean id=“orderService" class="cn.itcast.OrderServiceBean"/ ...

  9. spring实例化bean的三种方式

    公共使用的实体

随机推荐

  1. bootstrapValidator验证的remote中data属性里获取select一直是默认值

    budgetEditionNo:{ message:'版本号输入不正确' , validators:{ notEmpty:{ message:'版本号不能为空,请填写' } , remote:{ ur ...

  2. Anroid关于fragment控件设置长按事件无法弹出Popupwindows控件问题解决记录

    一.问题描述     记录一下最近在安卓的gragment控件中设置长按事件遇见的一个坑!!!     在正常的activity中整个活动中设置长按事件我通常实例化根部局,例如LinearLayout ...

  3. springmvc与swagger2

    首先呢我们导入相关的jar包文件 为了方便copy我copy一份 <!-- 导入java ee jar 包 -->        <dependency>           ...

  4. html5插件完成滚屏幕效果

    首先想要完成这样的效果要用到jquery-fullpage插件我们需要他的js文件和css样式文件如图  因为是jquery的插件所以我们还要导入jquery-min.js 在页面引入这些样式和插件 ...

  5. duid 配置监控

    web.xml中加入 <servlet> <servlet-name>DruidStatView</servlet-name> <servlet-class& ...

  6. 【04】openlayers 地图弹框

    效果: 创建地图: //创建地图 var map = new ol.Map({ //设置显示地图的视图 view: new ol.View({ projection: 'EPSG:4326', //投 ...

  7. 测试必知必会系列- Linux常用命令 - mv

    21篇测试必备的Linux常用命令,每天敲一篇,每次敲三遍,每月一循环,全都可记住!! https://www.cnblogs.com/poloyy/category/1672457.html 移动当 ...

  8. (转)协议森林10 魔鬼细节 (TCP滑窗管理)

    协议森林10 魔鬼细节 (TCP滑窗管理) 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在TCP协议与"流" ...

  9. CSS每日学习笔记(2)

    7.31.2019 1.CSS定位:允许你定义元素框相对于其正常位置应该出现的位置,或者相对于父元素.另一个元素甚至浏览器窗口本身的位置. CSS 有三种基本的定位机制:普通流.浮动和绝对定位.除非专 ...

  10. 各种WAF绕过手法学习

    原文:https://mp.weixin.qq.com/s/aeRi1lRnKcs_N2JLcZZ0Gg 0X00    Fuzz/爆破 fuzz字典 1.Seclists/Fuzzing https ...