1 Bean配置

Spring可以看做是一个管理Bean的工厂,开发者需要将Bean配置在XML或者Properties配置文件中。实际开发中常使用XML的格式,其中<bean>中的属性或子元素如下:

  • idBeanBeanFactory中的唯一标识,在代码中通过BeanFactory获取Bean的实例时候需要以此作为索引
  • classBean的具体实体类,使用包名+类名的形式指定
  • scope:指定Bean实例的作用域
  • <constructor-arg>:使用构造方法注入,指定构造方法的参数,index表示序号,ref指定对BeanFactory中其他Bean的引用关系,type指定参数类型,value指定参数常量值
  • <property>:用于设置一个属性,表示使用setter注入,name指定属性的名字,value指定要注入的值,ref指定注入的某个Beanid
  • <list>:用于封装List或者数组类型的依赖注入
  • <map>:封装Map类型的依赖注入
  • <set>:封装Set类型的依赖注入
  • <entry><map>的子元素,用于设置一个键值对

2 Bean实例化

Spring实例化Bean有三种方式:

  • 构造方法实例化
  • 静态工厂实例化
  • 实例工厂实例化

下面进行简单的演示。

2.1 构造方法实例化

Spring可以调用Bean对应的类的无参构造方法进行实例化,比如:

public class TestBean {
public TestBean()
{
System.out.println("构造方法实例化");
}
}

配置文件如下:

<bean id="testBean" class="TestBean"/>

则会调用无参构造方法初始化。

其实就是只写一个<bean>就可以了,默认的话会调用无参构造方法初始化。

2.2 静态工厂实例化

静态工厂实例化需要在工厂类中配置一个静态方法来创建Bean,并添加factory-method元素,首先创建工厂类:

public class TestBeanFactory {
private static final TestBean testBean = new TestBean();
public static TestBean getInstance()
{
return testBean;
}
}

接着配置文件通过class指定该工厂类,通过factory-method指定获取实例的方法:

<bean id="testBeanFactory" class="TestBeanFactory" factory-method="getInstance"/>

这样就可以通过id获取了:

TestBean test = (TestBean) context.getBean("testBeanFactory");

2.3 实例工厂实例化

实例工厂实例化与静态工厂实例化类似,不过是非静态方法,然后加上一个factory-bean元素,同样首先创建工厂类:

public class TestBeanFactory {
public TestBean getInstance()
{
return new TestBean();
}
}

在配置文件需要添加两个Bean,一个指定工厂类,一个指定使用哪一个工厂类以及使用工厂类的哪一个方法:

<bean id="factory" class="TestBeanFactory" /> <!--指定工厂类-->
<bean id="testBeanFactory" factory-bean="factory" factory-method="getInstance" /> <!--指定工厂Bean以及哪一个工厂方法-->

获取:

TestBean test = (TestBean) context.getBean("testBeanFactory");

3 Bean作用域

3.1 分类

<bean>中的scope可以指定的作用域如下:

  • singleton:默认作用域,在Spring容器只有一个Bean实例
  • prototype:每次获取Bean都会返回一个新的实例
  • request:在一次HTTP请求中只返回一个Bean实例,不同HTTP请求返回不同的Bean实例,仅在Spring Web应用程序上下文使用
  • session:在一个HTTP Session中,容器将返回同一个Bean实例,仅在Spring Web应用程序上下文中使用
  • application:为每个ServletContext对象创建一个实例,即同一个应用共享一个Bean实例,仅在Spring Web应用程序上下文使用
  • websocket:为每个WebSocket对象创建一个Bean实例,仅在Spring Web应用程序上下文使用

下面具体说一下最常用的两个:singletonprototype

3.2 singleton

scope设置为singleton时,Spring IoC仅生成和管理一个Bean实例,使用id/name获取Bean实例时,IoC容器返回共享的Bean实例。设置方式如下:

<bean id="testBean" class="TestBean"/>
<bean id="testBean" class="TestBean" scope="singleton"/>

因为这是默认的作用域,设置的话IDE也智能提示是多余的:

所以通过不需要加上scope,测试例子:

TestBean test1 = (TestBean) context.getBean("testBean");
TestBean test2 = (TestBean) context.getBean("testBean");
System.out.println(test1 == test2);

输入的结果为True

3.3 prototype

每次获取Bean时都会创建一个新的实例,例子如下:

<bean id="testBean" class="TestBean" scope="prototype"/>
TestBean test1 = (TestBean) context.getBean("testBean");
TestBean test2 = (TestBean) context.getBean("testBean");
System.out.println(test1 == test2);

测试结果为False

4 Bean生命周期

Spring可以管理作用域为singleton的生命周期,在此作用域下Spring能精确知道Bean何时被创建,何时初始化完成以及何时被摧毁。Bean的整个生命周期如下:

  • 实例化Bean
  • 进行依赖注入
  • 如果Bean实现了BeanNameAware,调用setBeanName
  • 如果Bean实现了BeanFactoryAware,调用setBeanFactory
  • 如果Bean实现了ApplicationContextAware,调用setApplicationContext
  • 如果Bean实现了BeanPostProcessor,调用postProcessBeforeInitialization
  • 如果Bean实现了InitializingBean,调用afterPropertiesSet
  • 如果配置文件配置了init-method属性,调用该方法
  • 如果实现了BeanPostProcessor,调用postProcessAfterInitialization,注意接口与上面的相同但是方法不一样
  • 不需要时进入销毁阶段
  • 如果Bean实现了DisposableBean,调用destroy
  • 如果配置文件配置了destroy-method,调用该方法

下面用代码进行演示:

public class TestBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, BeanPostProcessor, InitializingBean, DisposableBean {
public TestBean()
{
System.out.println("调用构造方法");
} @Override
public void setBeanName(String s) {
System.out.println("调用BeanNameAware的setBeanName");
} @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("调用BeanFactoryAware的setBeanFactory");
} @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("调用ApplicationContextAware的setApplicationContext");
} @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("调用BeanPostProcessor的postProcessBeforeInitialization");
return null;
} @Override
public void afterPropertiesSet() throws Exception {
System.out.println("调用InitializingBean的afterPropertiesSet");
} public void initMethod()
{
System.out.println("调用XML配置的init-method");
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("调用BeanPostProcessor的postProcessAfterInitialization");
return null;
} @Override
public void destroy() throws Exception {
System.out.println("调用DisposableBean的destroy");
} public void destroyMethod()
{
System.out.println("调用XML配置的destroy-method");
}
}

配置文件如下,指定了init-method以及destroy-method

<bean id="testBean" class="TestBean" init-method="initMethod" destroy-method="destroyMethod"/>

测试:

public static void main(String[] args) {
ConfigurableApplicationContext context = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
TestBean test = (TestBean) context.getBean("testBean");
((BeanDefinitionRegistry) context.getBeanFactory()).removeBeanDefinition("testBean");
}

输出如下:

如果没有最后一行的手动删除Bean定义是不会看见最后两行的输出的,另外,这里没有调用BeanPostProcessor接口的两个方法,如果把scope改为prototype,输出如下:

可以看到首先对Bean进行一次初始化,并且再次生成一个新的实例,而且调用了BeanPostProcessor的两个方法。但是需要注意Spring不会管理scopeprototype的销毁,所以图中没有看到调用销毁的方法。

5 Bean装配方式

Spring支持以下两种装配方式:

  • 基于XML装配
  • 基于注解装配
  • 显式Bean装配

Bean的装配方式也就是Bean的依赖注入方式,下面分别进行阐述。

5.1 基于XML装配

基于XML装配也就是在XML文件中指定使用构造方法注入或者setter注入,比如:

public class TestBean {
private final List<String> stringList;
private String s; public TestBean(List<String> stringList) {
this.stringList = stringList;
} public void setS(String s)
{
this.s = s;
} @Override
public String toString() {
return stringList.toString() + "\n" + s + "\n";
}
}

Bean有一个带参数的构造方法以及一个setter,接着在XML中指定相应的值即可:

<bean id="testBean" class="TestBean">
<constructor-arg index="0">
<list>
<value>1</value>
<value>2</value>
</list>
</constructor-arg>
<property name="s" value="444" />
</bean>

测试:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(context.getBean("testBean"));

5.2 基于注解装配

尽管XML方式可以简单地装配Bean,但是一旦Bean过多就会造成XML文件过于庞大,不方便以后的升级和维护,因此推荐使用基于注解的装配方式,先来看一下常用的注解:

  • @Autowired:自动装配,默认按照Bean的类型进行装配,这是Spring的注解
  • @Resource:与@Autowired类似,但是是按名称进行装配,当找不到与名称匹配的Bean时才按照类型进行装配,这是JDK的注解
  • @Qualifier:与@Autowired配合使用,因为@Autowired默认按Bean类型进行装配,使用@Qualifier可以按名称进行装配
  • @Bean:方法上的注解,用于产生一个Bean,然后交由Spring管理
  • @Component:表示一个组件对象,加上了该注解就能实现自动装配,默认的Beanid为使用小驼峰命名法的类
  • @Repository/@Service/@Controller:实际上是@Component的别名,只不过是专门用于持久层/业务层/控制层的,从源码可以看出三个注解的定义除了名字不一样其他都一致,并且都是@Component的别名:

官方文档也提到相比起使用@Component,使用@Repository/@Service/@Controller在持久层/业务层/控制层更加合适,而不是统一使用@Component

5.3 注解使用示例

5.3.1 @Bean

@Bean示例如下:

public class TestBean implements BeanNameAware{
@Override
public void setBeanName(String s) {
System.out.println("setBeanName");
}
} @Configuration
public class Config {
@Bean
public TestBean getBean()
{
return new TestBean();
}
} public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
context.getBean("getBean");
}
}

注意通过@Bean自动产生的Beanid为方法名,而不是Bean的类名的小驼峰形式。

5.3.2 其他

@Autowired/@Resource/@Qualifier/@Repository/@Service/@Controller综合示例,首先创建如下包以及文件:

@Controller
public class TestController {
@Resource
private TestService service; public void save()
{
System.out.println("controller save");
service.save();
}
}
@Service
public class TestService {
@Autowired
@Qualifier("testRepository1")
private TestInterface repository1; @Autowired
@Qualifier("testRepository2")
private TestInterface repository2;
public void save()
{
System.out.println("service save");
repository1.save();
repository2.save();
}
}
@Repository
public class TestRepository1 implements TestInterface{
@Override
public void save() {
System.out.println("repository1 save");
}
}
@Repository
public class TestRepository2 implements TestInterface{
@Override
public void save() {
System.out.println("repository2 save");
}
}
public interface TestInterface {
void save();
}
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
((TestController)context.getBean("testController")).save();
}
}

配置文件:

<context:component-scan base-package="bean" />

TestService中,使用了@Qualifier

@Autowired
@Qualifier("testRepository1")
private TestInterface repository1; @Autowired
@Qualifier("testRepository2")
private TestInterface repository2;

因为TestInterface有两个实现类,@Autowired不知道是选择TestRepository1还是TestRepository2,因此需要加上@Qualifier,指定需要注入的Beanid,或者使用@Resouce

@Resource
private TestInterface testRepository1; @Resource
private TestInterface testRepository2;

但是要注意这样默认了成员的名字就是Beanid,可以看到这里的名字是testRepository1testRepository2而不是repository1repository2

Spring 学习笔记(三):Spring Bean的更多相关文章

  1. Spring学习笔记三:Bean管理

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6775827.html  一:如何使用Spring获取对象 1:定义bean类:要按照注入方式来定义对应的bea ...

  2. spring学习笔记(一) Spring概述

    博主Spring学习笔记整理大部分内容来自Spring实战(第四版)这本书.  强烈建议新手购入或者需要电子书的留言. 在学习Spring之前,我们要了解这么几个问题:什么是Spring?Spring ...

  3. Java架构师之路 Spring学习笔记(一) Spring介绍

    前言 这是一篇原创的Spring学习笔记.主要记录我学习Spring4.0的过程.本人有四年的Java Web开发经验,最近在面试中遇到面试官总会问一些简单但我不会的Java问题,让我觉得有必要重新审 ...

  4. Spring学习笔记(三)之装配Bean

    除了组件扫描与自动装配之外还有基于Java代码的装配与基于XML的装配. 有一些场景是我们不能用自动装配的,比如我们要给第三方库中的组件装配到我们的应用中,这时自动装配无效,因为自动装配只能扫描本应用 ...

  5. Spring学习笔记之 Spring IOC容器(二) 之注入参数值,自动组件扫描方式,控制Bean实例化方式,使用注解方式

     本节主要内容:    1. 给MessageBean注入参数值    2. 测试Spring自动组件扫描方式    3. 如何控制ExampleBean实例化方式    4. 使用注解方式重构Jdb ...

  6. Spring学习笔记之 Spring IOC容器(一)之 实例化容器,创建JavaBean对象,控制Bean实例化,setter方式注入,依赖属性的注入,自动装配功能实现自动属性注入

    本节主要内容:       1.实例化Spring容器示例    2.利用Spring容器创建JavaBean对象    3.如何控制Bean实例化    4.利用Spring实现bean属性sett ...

  7. 1.2(Spring学习笔记)Spring中的Bean

    一.<Bean>的属性及子元素 在1.1中我们对<Bean>有了初步的认识,了解了一些基本用法. 现在我们进一步理解<Bean>属性及子元素. 我们先来看下< ...

  8. Spring 学习笔记(2) Spring Bean

    一.IoC 容器 IoC 容器是 Spring 的核心,Spring 通过 IoC 容器来管理对象的实例化和初始化(这些对象就是 Spring Bean),以及对象从创建到销毁的整个生命周期.也就是管 ...

  9. [Spring学习笔记 1 ] Spring 简介,初步知识--Ioc容器详解 基本原理。

    一.Spring Ioc容器详解(1) 20131105 1.一切都是Bean Bean可是一个字符串或者是数字,一般是一些业务组件. 粒度一般比较粗. 2.Bean的名称 xml配置文件中,id属性 ...

  10. Spring学习笔记之Spring概述

    概述   Spring是一个java应用最广的开源框架,它是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Deve ...

随机推荐

  1. Mysql训练:where后不可以进行聚合函数的判断,而having可以进行聚合函数的判断

    力扣题目:查找重复的电子邮箱 编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱. +----+---------+ | Id | Email | +----+---------+ | ...

  2. Spring注解@PropertySource加载配置文件和SpringBoot注解@Value、@ConfigurationProperties进行属性映射

    SpringBoot的配置文件 位置:resources目录下 配置文件的作用: (1).SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用a ...

  3. WPF -- 自定义按钮

    本文介绍WPF一种自定义按钮的方法. 实现效果 使用图片做按钮背景: 自定义鼠标进入时效果: 自定义按压效果: 自定义禁用效果 实现效果如下图所示: 实现步骤 创建CustomButton.cs,继承 ...

  4. JAVA基础(二)—— 常用的类与方法

    JAVA基础(二)-- 常用的类与方法 1 Math类 abs ceil floor 绝对值 大于等于该浮点数的最小整数 小于等于该浮点数的最大整数 max min round 两参数中较大的 两参数 ...

  5. 关于Java高并发编程你需要知道的“升段攻略”

    关于Java高并发编程你需要知道的"升段攻略" 基础 Thread对象调用start()方法包含的步骤 通过jvm告诉操作系统创建Thread 操作系统开辟内存并使用Windows ...

  6. 后端程序员之路 3、fastcgi、fastcgi++

    CGI与FastCGI - wanghetao - 博客园http://www.cnblogs.com/wanghetao/p/3934350.html eddic/fastcgipp: A C++ ...

  7. PVE更新WEB管理地址

    PVE也是一台Linux系统,如果PVE更换了网络环境,比如从家里拿到了办公室,那么就需要对其更新网络,才能让其它机器访问到它的8006管理地址. 具体做法是通过修改配置文件来更改IP. 更新网卡配置 ...

  8. 基于Hi3559AV100的视频采集(VDEC-VPSS-VO)整体框图设计

    下面给出基于Hi3559AV100的视频采集整体设计,具体设计将在后续给出: 图形采集端整体设计 Hi3559AV100软件程序按结构划分可分为4层,第一层是硬件驱动层,第二层是操作系统层,第三层是媒 ...

  9. Java 面向对象 04

    面向对象·四级 多态的概述及其代码实现 * A:多态(polymorphic)概述 * 事物存在的多种形态 * B:多态前提 * a:要有继承关系 * b:要有方法重写 * c: 要有父类引用指向子类 ...

  10. Linux下找出吃内存的方法总结

    Linux下查询进程占用的内存方法总结,假设现在有一个「php-cgi」的进程 ,进程id为「25282」. 现在想要查询该进程占用的内存大小.linux命令行下有很多的工具进行查看,现总结常见的几种 ...