1,一切都是Bean

Bean是Spring应用程序中(其实是Spring容器中)的基本元素,在Spring框架上运行的应用程序,就是由一个又一个的Bean组合在一起、像搭积木一样堆出来的。所有的Bean都由Spring的核心容器负责管理、创建、销毁,同时Bean之间的相互依赖也由Spring容器中的依赖注入功能自动管理。

1.1bean的作用域

  • lsingleton:定义bean的范围为每个Spring容器一个实例(默认值)
  • lprototype:定义bean可以被多次实例化(使用一次就创建一次)
  • lrequest:定义bean的范围是HTTP请求,只有再使用有web能力的spring上下文时有效。
  • lsession:定义bean的范围是HTTP会话,只有再使用有web能力的spring上下文时有效。
  • lglobal-session:定义bean的范围是全局HTTP会话,只有再portlet上下文中有效。

1.2 三种实例化bean的方式

  • 使用构造器实例化(默认无参数)

<bean id="person" class="com.xiaohui.domain.Person"/>

  • 使用静态工厂方法实例化(简单工厂模式)

<bean id="person" class="com.xiaohui.app.create.PersonFactory" factory-method="getPersonInstance"/>

public class PersonFactory {public static Person getPersonInstance(){return new Person();}
}
  • 使用实例工厂方法实例化(工厂方法模式)

<bean id="personFactory" class="com.xiaohui.app.create.PersonFactory" />

<bean id="person" factory-bean="personFactory" factory-method="createtPersonInstance"/>

public class PersonFactory{public  Person createtPersonInstance(){return new Person();}
}

1.3 指定Bean的初始化方法和销毁方法

spring初始化bean或销毁bean时有时候需要执行一些处理工作,因此spring可以在创建或者销毁bean时可以调用bean的两个生命周期方法

<bean id="personService" class="com.xiaohui.service.PersonServiceImpl"
   init-method="init"
   destroy-method="distory" scope="singleton" />

(注意的是只有scope=singleton的bean,destroy-method才有效)

1.4 bean 的生命周期

  1. 实例化bean
  2. 设置属性值
  3. 设置bean名称(如果bean实现了BeanNameAware接口)
  4. 设置beanFactory(如果bean实现了BeanFactoryAware接口)
  5. 设置ApplicationContext(如果bean实现了ApplicationContextAware接口)
  6. 前预处理(如果上下文中存在多个BeanPostProcessor,将调用其postProcessBeforeInitialization()方法)
  7. 初始化Bean(如果bean实现了InitializingBean,将调用其afterPropertiesSet方法,如果bean声明了自定义初始化方法,调用)
  8. 后预处理(如果上下文中存在多个BeanPostProcessors,将调用其postProcessAfterInitialization()方法)
  9. Bean创建完成,待用
  10. 销毁Bean(如果bean实现了DisposableBean,调用其destroy()方法)
  11. 销毁Bean(如果bean声明了自定义的销毁方法,调用)
1.5 bean的继承
在spring的继承中不论在java类的实际情况中是否存在真正的extends继承关系,只要其存在引用相同的属性值,在spring的bean管理都可以将其抽象为继承关系。在spring的xml配置中可将引用相同属性的属性property抽出一个父类bean。该bean需要设计其abstract属性为true。其他“继承”该bean的bean需要制定其parent属性值为该抽象父类的id。如下在studentDao和teacherDao中都存在属性sf(SessionFactory),则可以抽出一个父类。
<bean id="sessionFactory" class="com.xiaohui.test.SessionFactory" />
<bean id="baseDao" abstract="true"><property name="sf" ref="sessionFactory" />
</bean><bean id="studentDao" class="com.xiaohui.service.impl.StudentDaoImpl" parent="baseDao" />
<bean id="teacherDao" class="com.xiaohui.service.impl.TeacherDaoImpl" parent="baseDao" />

2,依赖注入(Dependency Injection)

所谓的依赖注入就是在于行期间,由外部容器动态的将依赖对象注入到组件中。通俗的讲也就是不在程序中显示的调用该类的setter()方法去设置该类的属性。而是由spring容器处理经过程序员配置的xml来设置该类的属性值。

所谓的控制反转(Inversion of Control)就是指应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转,目的是为了获得更好的扩展性和良好的可维护性。

通常的依赖注入有手工装配(配置xml)和自动装配(基于注解)的两种方式方式:

2.1通过setter方法注入依赖

  • <bean>元素的<property>子元素指明了使用该bean的setter方法来注入

    1.可以使用property的value属性来进行简单类型的注入

<bean id="person" class="com.xiaohui.domain.Person"><property name="id" value="1"/><property name="name" value="张三丰"/>
</bean>

2.使用ref引用其他的bean

<bean id="person" class="com.xiaohui.bean.Person" />
<bean id="personService" class="com.xiaohi.bean.impl.PersonServiceImpl"><!-- 引用类型 --><property name="person" ref="person" />
</bean>

3.内部bean

<bean id="personService" class="com.xiaohui.bean.impl.PersonServiceImpl"><!-- 内部bean注入 --><property name="person"><bean class="com.xiaohui.bean.Person" /></propert>
</bean>

使用该方式的缺点就是无法在其他地方使用这个类,该类只能为外部的bean使用。

4.装配集合

  <!-- 装配list --><property name="lists"><list><value>list1</value><ref bean="person" /></list></property><!-- 装配数组 --><property name="obj"><list><value>obj1</value><ref bean="person" /></list></property><!-- 装配set set使用方法和list一样,不同的是对象被装配到set中,而list是装到 List或数组中装配--><property name="sets"><set><value>set1</value><value>set2</value><ref bean="person" /></set></property><!-- 装配map map中的<entry>的数值和<list>以及<set>的一样可以使任何有效的属性元素,需要注意的是key值必须是String的。--><property name="maps"><map><entry key="01" value="map01" /><entry key="02" value="map02" /><entry key-ref="refkeybean" value-ref="refvaluebean"></map></property><property name="props"><props><prop key="01">prop1</prop><prop key="02">prop2</prop></props></property><!-- 简化写法 --><property name="props"><value>01=prop102=prop2</value></property>

5.设空值null

<!-- 装配null --><property name="listnull"><null/></property>

6,自定义String2Object类型转换器来设置属性

在该属性类的同一包下面创建类 名称 PropertyClassNameEditor,并继承PropertyEditorSupport类,复写其setAsText(String text)方法即可。

例如给Family类的Person类属性创建一个String2Person类的类型转换器。

public class PersonEditor extends PropertyEditorSupport {@Overridepublic void setAsText(String text) throws IllegalArgumentException {if(text!=null){String[] props = text.split("-");if(props!=null && props.length == 3){Person p = new Person();p.setId(Long.parseLong(props[0]));p.setName(props[1]);p.setMail(props[2]);this.setValue(p);}}}
}

Family类:

public class Family {private Person master;public void setMaster(Person master) {this.master = master;}public void sayMaster(){System.out.println(master);}
}

Person类:

public class Person {private Long id;private String name;private String mail;public String getMail() {return mail;}public void setMail(String mail) {this.mail = mail;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Person [id=" + id + ", name=" + name + ", mail=" + mail + "]";}
}

则可以这样给Family 类注入Person类的master属性值

<bean id="family" class="com.xiaohui.domain.Family"><property name="master" value="3-jack-jack@163.com"/>
</bean> 

7,通过加载properties文件为bean属性设值
需要引入context命名空间: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/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><context:property-placeholder location="classpath:jdbc.properties"/><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean>
</beans>

jdbc.properties内容如下:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring2
jdbc.username=root
jdbc.password=root

2.2.  通过构造函数注入依赖

Person类:

package com.xiaohui.domain;public class Person {private Long id;private String name;private String mail;public Person() {}public Person(Long id, String name, String mail) {this.id = id;this.name = name;this.mail = mail;}public String getMail() {return mail;}public void setMail(String mail) {this.mail = mail;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Person [id=" + id + ", name=" + name + ", mail=" + mail + "]";}
}

1.可以按照参数的类型注入,如:

<bean id="person" class="com.xiaohui.domain.Person"><constructor-arg type="Long" value="2" /><constructor-arg type="String" value="herry" /><constructor-arg type="String" value="herry@qq.com" />
</bean>

当一种类型有多个的种情况下其按照构造函数的参数顺序注入。如上,其第二个constructor-arg标签注入的为Person的name属性。

2.可以按照参数的name进行注入,如:

 <bean id="person" class="com.xiaohui.domain.Person"><constructor-arg name="id" value="2" /><constructor-arg name="name" value="herry" /><constructor-arg name="mail" value="herry@qq.com" /></bean>

其中name的值为该类的构造方法的参数名。正常情况下,通过软件自动生成的构造方法其参数名和对应的属性名是一样的。

3.可以按照索引(构造函数的参数顺序)进行注入

<bean id="person" class="com.xiaohui.domain.Person"><constructor-arg index="0" value="2" /><constructor-arg index="1" value="herry" /><constructor-arg index="2" value="herry@qq.com" />
</bean> 

2.3 通过自动装配的方式进行注入

通过设置bean标签中的autowire属性。

autowire的取值为:byType:按类型装配,可以根据属性的类型,在容器中寻找跟该类型匹配的bean。如果发现多个,那么将会抛出异常。如果没有找到,即属性值为null。

                               byName:按名称装配,可以根据属性的名称,在容器中寻找跟该属性名相同的bean,如果没有找到,即属性值为null。

                              constructor:与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。

byType

autowire-candidate:可选值为 true|false  当autowire匹配时有多个类型的时候,使用该属性可以表明该bean是否为优先的候选bean 通常设置哪些bean不为优先候选的

<bean id="util" class="com.xiaohui.myinject.DbUtil" />
<bean id="util2" class="com.xiaohui.myinject.DbUtil" autowire-candidate="false" />
<bean id="dao" class="com.xiaohui.myinject.PersonDaoImpl" autowire="byType"/>
<bean id="personService" class="com.xiaohui.myinject.PersonServiceImpl" autowire="byType"/>

byName bean的id要和依赖该bean的类中的属性名一样.

<bean id="util" class="com.xiaohui.myinject.DbUtil" />
<bean id="dao" class="com.xiaohui.myinject.PersonDaoImpl" autowire="byName"/>
<bean id="personService" class="com.xiaohui.myinject.PersonServiceImpl" autowire="byName"/>

2.4 通过注解方式进行装配

在使用注解方式进行注入之前呢,必须现在spring配置文件applicationContext.xml中引入context命名空间

再在配置文件中加入<context:annotation-config/>标签

<?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/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><context:annotation-config/><bean id="util" class="com.xiaohui.myinject2.DbUtil" /><bean id="personDao" class="com.xiaohui.myinject2.PersonDaoImpl" /><bean id="personService" class="com.xiaohui.myinject2.PersonServiceImpl" />
</beans>

常用的注解说明:

@Autowire   &  @Resource  & @Qualifier

@Autowire和@Resource的区别是:@Autowired 默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
相同的是:都可以直接使用在Field上或者setter方法之上。
@Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。
@Resource可以通过设置name属性指定注入bean的名称,但一旦指定了name属性,就只能按名称装配了
如果我们想使用按名称装配,可以让@Autowired结合@Qualifier注解一起使用。

对应Spring配置文件中的init-method和destory-method,在bean中,可以直接使用@PostConstruct和@PreDestory标签来标记生命周期方法。
public class CachingMovieLister {
@PostConstruct
public void populateMovieCache() {
}
@PreDestroy
public void clearMovieCache() {
}
}
相当于:
<bean id="cachingMovieLister" class="CachingMovieLister" init-method="populateMovieCache" destory-method="clearMovieCache" />
 
更为简洁的bean管理方式:classpath自动扫描
在上面的配置中我们还需要在spring的xml文件中配置bean信息。spring为我们提供了另一种更为简洁的bean管理和依赖注入的的方式,成为classpath自动扫描。
使用@Component,@Controller,@Service,@Repository注释我们需要被spring管理的组件类
@Controller用于标注控制层组件(如struts中的action)。
@Service用于标注业务层组件。
@Repository用于标注数据访问组件,即DAO组件。
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

这时我们在xml文件中只需要加入<context:component-scan base-package="com.xiaohui.package"/>,这时我们就不用在xml中配置 base-package包下面的所有bean了。
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/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd"><context:annotation-config/><context:component-scan base-package="com.xiaohui.myinject2"/>
</beans>

java类如下:

Dbutil类:
package com.xiaohui.myinject2;
import org.springframework.stereotype.Component;
@Component
public class DbUtil {public void save(){System.out.println("save object in dbutil....");}
}

PersonDaoImpl类:
package com.xiaohui.myinject2;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class PersonDaoImpl {private DbUtil util;@Autowiredpublic void setUtil(DbUtil util) {this.util = util;}public void save(){System.out.println("save in PersonDaoImpl....");util.save();}
}
PersonServiceImpl类:
package com.xiaohui.myinject2;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class PersonServiceImpl {private PersonDaoImpl dao;@Autowiredpublic void setDao(PersonDaoImpl dao) {this.dao = dao;}public void save(){System.out.println("PersonServiceImpl save user.....");dao.save();}
}

PersonActionPersonActionPersonAction类:

package com.xiaohui.myinject2;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class PersonAction {private PersonServiceImpl service;@Autowiredpublic void setService(PersonServiceImpl service) {System.out.println("save in action.....");this.service = service;}public void execute(){service.save();}
}

测试类:

package com.xiaohui.app;import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.xiaohui.myinject2.PersonAction;public class AppTest {@Testpublic void testSpring() throws Exception {ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");PersonAction service = ctx.getBean(PersonAction.class);service.execute();}
}

打印结果:

save in action.....
PersonServiceImpl save user.....
save in PersonDaoImpl....
save object in dbutil....

spring 随笔(一) bean Dependency Injection相关推荐

  1. Spring MVC快速教程:依赖注入 Spring MVC Fast Tutorial: Dependency Injection

    What are we going to build? Use singletons of CarManager and BrandManager instead of creating multip ...

  2. Spring IoC容器和Dependency Injection模式

    轻松学习Spring<一> IoC容器和Dependency Injection模式 最近公司需要,项目中要用到Spring和Ibatis.趁着过年好好学习学习.Ibatis就如同Hibe ...

  3. IoC容器和Dependency Injection模式

    注:本文转自http://insights.thoughtworkers.org/injection/,请尊重译者的劳动成果,转载需注明出处. 2017年3月3日 by Martin Fowler L ...

  4. Inversion of Control Containers and the Dependency Injection pattern--Martin Fowler

    原文地址:https://martinfowler.com/articles/injection.html n the Java community there's been a rush of li ...

  5. 依赖注入(Dependency Injection)框架是如何实现的?

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/fuzhongmin05/ article/details/109572151 当创建对象是一件庞大又复杂的大工程的时候,我们一 ...

  6. Spring中的Bean配置

    IOC&DI概述 OPC(Inversion of Control):其思想是反转资源获取的方向.传统的资源查找方式要求组件向容器发起请求查找资源.作为回应,容器适时的返回资源.而应用了IOC ...

  7. IoC 容器和 Dependency Injection 模式[转]

    转自:插图版<IoC 容器和Dependency Injection 模式> 原文地址:Inversion of Control Containers and the Dependency ...

  8. IoC容器和 Dependency Injection模式 Inversion of Control Containers and the Dependency Injection pattern

    原文链接:http://www.martinfowler.com/articles/injection.html 文末有中文翻译版本,martinfowler上有提供中文版的pdf,也可以自行下载 中 ...

  9. 【5】依赖注入DI(Dependency Injection)

    6.依赖注入 概念 依赖注入(Dependency Injection,DI). 依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 . 注入 : 指Bean对象所依赖的资源 , 由 ...

最新文章

  1. 2010后的经济增长点再研究
  2. Python数据分析学习笔记
  3. markdown单元格快速合并(不用自己写html代码)
  4. 日志处理中一些shell命令技巧
  5. Linux按键输入实验(体验一下输入驱动,实际开发使用input子系统处理)
  6. 关于页面布局间距使用的经验之谈
  7. [css] 除了可以用js跟踪用户信息外,如果不用js,使用纯css怎么做呢?
  8. input子系统基础之按键5——按键驱动
  9. 利用python随机生成姓名的实例教程
  10. MySQL更换内存分配器
  11. ElementUI,和IView在Vue中的安装引入和配置
  12. Knowledge Distillation(知识蒸馏)Review--20篇paper回顾
  13. 用简单 JS 实现代替 MYBATIS LOG PLUGIN 的功能
  14. 四川麻将java_四川麻将纯AI算法------最优拆牌
  15. [转]Cookie详解
  16. 计算机网络拓扑有,计算机网络拓扑
  17. 再次出现用户净流失,大失颜面的中国移动推出超低价套餐争取用户
  18. 给你一个水杯如何进行测试?
  19. 江湖有故人!欢迎来到程序员的江湖
  20. html用css完成动画效果图,利用CSS Sprite实现PNG图片动画

热门文章

  1. 请拆招:将两个已排序集合分解成两个独立部分的集合和一个共有部分的集合?...
  2. idea 提示 Cannot resolve symbol ‘log‘解决
  3. python自增_Python 为什么不支持 i++ 自增语法,不提供 ++ 操作符?
  4. mysql 撤销删除_线上磁盘告警,mysql无法释放空间,踩了个大坑,大家记得别踩坑...
  5. IOS 长按默认事件阻止 【坑】
  6. 最安全的浏览器?黑客大赛微软Edge被破解5次夺下“冠军”
  7. DNS高速缓存及DDNS
  8. systemd 开机无法启动privoxy
  9. 专题实验 字符集(全球化支持)
  10. ivar layout 相关知识点