一.spring-core IoC container(1) container概述和Bean基础
来源:互联网 发布:光猫 连接端口23失败 编辑:程序博客网 时间:2024/06/02 15:51
一:IoC 控制反转
IoC 控制反转,也叫依赖注入。主要用于解决程序中的依赖关系维护问题。理解依赖注入需要理解两方面的内容:
1.什么是依赖
所谓依赖,简单来说就是如果类A中包含有类B的对象,那么传统方式构造B对象的方法是B a = new B()
,这就在A中形成了对B的依赖关系。
2.什么是注入?
所谓注入,拿上述实例来说,spring通过他的方式,也就是容器,将这些所依赖的对象统一管理起来,在程序中需要使用到的地方直接从容器中取得,这就好像是容器主动注入到程序中一样。
二:Container overview 容器概观
org.springframework.context.ApplicationContext
接口代表了IOC容器,他是初始化、配置、组装上述的Beans 而诞生的。常用的实现接口:ClassPathXmlApplicationContext
和 FileSystemXmlApplicationContext
分别是从classpath读取配置xml或者filesystem 读取 配置的xml 。 当然,现今metadata(元数据)的配置也可以通过java注解或者java代码实现。
2.1 Configuration metadata 元数据配置
传统的配置方式使用的是xml的配置,spring除了使用xml配置元数据以外,还允许使用 基于注解的配置方式 和 基于java-based的配置方式,现如今,很多开发者都是使用 java-based 的配置方式 , 本文分别对基于xml和java-based annocation 都进行了阐述
XML-based Configuration
配置格式:
<?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"> <import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <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>
其中,每一对<bean></bean>
代表了一个被注入的bean,其中的id
是一个确定bean身份的字符串,不可重复。class
代表的是类全名 这是id
身份对应的那个类。
容器初始化:
初始化容器很简单,如果配置文件在classpath下,可以直接使用
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
即可,关于ClassPath和FileSystem等Resource,将在第二章阐述。
配置文件导入方式:
在实际项目中,可能有很多配置文件对应不同的层级,如果需要一个统一的配置文件进行管理,这个时候就需要用到配置文件的导入,语法如下:
<beans> <!-- 相对路径 --> <import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <!-- 绝对路径 --> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/></beans>
resource使用相对路径和绝对路径均可
容器使用:
接口ApplicationContext
相当于一个大工厂,可以用于生产和维护各种经初始化的bean对象 主要使用方法:T getBean(String name, Class<T> requiredType)
// create and configure beansApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});// retrieve configured instancePetStoreService service = context.getBean("petStore", PetStoreService.class);// use configured instanceList<String> userList = service.getUsernameList();
三:Bean 概况
spring IoC 容器管理各种各样的Bean,这些bean的创建都会在容器中存在元数据配置。最直观的就是上述的xml配置。
容器内部,bean定义表示BeanDefinition
其中包含且不只有下面的信息:
- 类全名:bean对应的类
- bean的行为配置元素,bean在容器中的行为(包括范围、生命周期和请他等等)
- 和其他bean的依赖关系
- 其他配置来新创建的对象,比如连接bean的数量管理,数据库连接池池大小。
Bean 定义
属性:
- class
- name
- scope
- constructor arguments
- properties
- autowiring mode
- initialization method
- destruction method
下面对这些属性进行说明:
class:
- 典型的通过在容器的bean中配置class属性将对应的class交给容器管理,避免在程序中使用的时候使用
new
方法 - 静态内部类的配置:
class="com.example.Foo$Bar"
其中Bar 是Foo的静态内部类
name:
一般而言,每一个bean的id是唯一的,但是name却可以有多个,他们可以通过别名进行区分:
<alias name="subsystemA-dataSource" alias="subsystemB-dataSource"/><alias name="subsystemA-dataSource" alias="myApp-dataSource" />
constructor arguments:
基于构造方法的注入:
如果bean的构造中包含有依赖关系,及包含其他对象。比如:
package x.y;public class Foo { private int year; public Foo(Bar bar, Baz baz,int year) { // ... }}
可以用过使用如下配置:
<beans> <bean id="foo" class="x.y.Foo"> <constructor-arg ref="bar"/> <constructor-arg ref="baz"/> <!--构造中包含有基本类型或者String --> <constructor-arg type="int" value="7500000"/> <!--如果有多个基本类型或者String 也可以使用 “index”--> <!--<constructor-arg index="0" value="7500000"/>--> <!--还可以直接使用属性的名字--> <!--<constructor-arg name="year" value="7500000"/>--> </bean> <bean id="bar" class="x.y.Bar"/> <bean id="baz" class="x.y.Baz"/></beans>
基于Setter方法的注入:
如果你的bean中设置了该属性的setter方法,可以使用setter注入
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"/>
对于construct注入和setter注入是可以混用的,一般而言,对于一些强制的依赖优先选用construct注入 而 非强制的以来可以使用setter注入,当然,在setter方法上使用@Require
注解表示该依赖需要强制注入。
properties:
在上述setter注入中已有所阐述,表示bean中的属性,通过value或者ref
赋值
在使用properties时候,也有一种简化的写法,如下:
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <!-- results in a setDriverClassName(String) call --> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydb"/> <property name="username" value="root"/> <property name="password" value="masterkaoli"/></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"> <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/mydb" p:username="root" p:password="masterkaoli"/></beans>
注意需要导入p-namespace
对于内部类中的bean的属性赋值:
<bean id="outer" class="..."> <!-- instead of using a reference to a target bean, simply define the target bean inline --> <property name="target"> <bean class="com.example.Person"> <!-- this is the inner bean --> <property name="name" value="Fiona Apple"/> <property name="age" value="25"/> </bean> </property></bean>
对于Collections的配置:
<bean id="moreComplexObject" class="example.ComplexObject"> <!--配置 java.util.Properties--> <property name="adminEmails"> <props> <prop key="administrator">administrator@example.org</prop> <prop key="support">support@example.org</prop> <prop key="development">development@example.org</prop> </props> </property> <!-- 配置 java.util.List --> <property name="someList"> <list> <value>a list element followed by a reference</value> <ref bean="myDataSource" /> </list> </property> <!-- 配置 java.util.Map --> <property name="someMap"> <map> <entry key="an entry" value="just some string"/> <entry key ="a ref" value-ref="myDataSource"/> </map> </property> <!-- 配置 java.util.Set --> <property name="someSet"> <set> <value>just some string</value> <ref bean="myDataSource" /> </set> </property></bean>
spring默认使用 eagerly create 即 急加载的方式 初始化所有单例bean 的,这样的目的主要是在程序启动的时候就可以检测bean初始化存在的错误 可以通过 设置 lazy-init="true" 来设置为懒加载
Autowiring:
spring容器可以自动相互合作的beans,在<bean/>
的属性中加入autowire
元素,自动装配有四种模式:
- no : (默认)不使用自动装配
- byName: 通过name属性进行自动装配,比如:如果一个bean在定义的时候设置了byname 自动装配, 该bean包含了了一个
master
属性和对应的setter方法,spring 会被命名master
的bean 将其设值到前一个bean中。 - byType : 通过类型自动装配,要求容器中不得多余一个该类型的bean,不然会抛出异常。
- constructor :和byType类似 但是用在构造参数中
**自动装配的优点和缺点:**优点:1.自动装配减少配置具体属性和构造参数的必要性2.自动装配能根据对象的改变更新配置,如果你需要在类中增加依赖,那么并不需要改变该类对应bean的配置。缺点和限制:1.如果在bean中有明确的配置对应的property或者构造参数的值,那么该值会覆盖自动装配,基本类型和String不能自动装配2.明确的配置会比自动装配更家准确3.自动装配的对象不得出现多次,不然会报错
在<bean/>中设置autowire-candidate=false会取消自动装配,即使使用了 @Autowired注解
initialization method:
org.springframework.beans.factory.InitializingBean
接口允许bean在必要属性被设值后做一些初始化的操作,一般不推荐直接使用这个接口,而是使用@PostConstruct
具体的POJO初始化方法,xml配置中,可以使用 init-method
来配置初始化
void afterPropertiesSet() throws Exception;
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean { public void init() { // do some initialization work }}
destruction method:
org.springframework.beans.factory.DisposableBean
接口 允许bean在destroy的时候执行一些后续动作,推荐使用注解@PreDestroy
void destroy() throws Exception;
或者在xml中配置
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean { public void cleanup() { // do some destruction work (like releasing pooled connections) }}
Method injection 方法注入:
如果一个bean中依赖另外一个bean,但是两个bean的生命周期不一样,这时候将导致程序出现问题。
一种解决方法是放弃一些控制反转,
import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;//实现该接口后,容器会将ApplicationContext 自动设值给该beanpublic class CommandManager implements ApplicationContextAware { private ApplicationContext applicationContext; public Object process(Map commandState) { // grab a new instance of the appropriate Command Command command = createCommand(); // set the state on the (hopefully brand new) Command instance command.setState(commandState); return command.execute(); } protected Command createCommand() { // notice the Spring API dependency! return this.applicationContext.getBean("command", Command.class); } public void setApplicationContext( ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }}
上述方法中,通过实现ApplicationContextAware
获取 applicationContext
对象 ,使得应用可以在需要的时候获取不同生命周期的bean,这样做的代价是放弃了一下ioc的特性。
Lookup method injection 使用lookup-method属性
先看一个例子:
public abstract class CommandManager { public Object process(Object commandState) { Command command = createCommand(); command.setState(commandState); return command.execute(); } protected abstract Command createCommand();}
在上述的类中有一个抽象方法,此方法返回值是 一个对象,在spring中,可以通过在<bean/>
中加上lookup-method
自动形成这个抽象方法的实现。
<!-- a stateful bean deployed as a prototype (non-singleton) --><bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype"> <!-- inject dependencies here as required --></bean><!-- commandProcessor uses statefulCommandHelper --><bean id="commandManager" class="fiona.apple.CommandManager"> <lookup-method name="createCommand" bean="myCommand"/></bean>
这种形式的注入有一定条件:
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
也可以在bean的方法中使用@Lookup("myCommand")
注解
scope
在容器中初始化一个bean的同时,相当与创建了一个bean的“处方”,具体如何是配置,是由自己配置了。我们可以通过同一个“处方”根据需要创建出对应数量的bean,bean的scope分为7种:
- singleton : (默认)单例bean,spring 每个IoC容器中只有一个bean
- prototype: IoC容器中有多个bean
- request:每一个HTTP Request请求会创建一个bean
- session:每一个Session的生命周期中有一个bean,只在web应用中有用
- globalSession : 每一个globalSession 的生命周期中有一个bean,只在web应用中有用
- application:每一个application的生命周期中有一个bean,只在web应用中有用
- websocket:每一个websocket的生命周期中有一个bean,只在web应用中有用
- 一.spring-core IoC container(1) container概述和Bean基础
- 【Java.Spring.Core】【IoC】IoC容器 - Container
- 初识Spring IoC container
- 一.spring-core IoC container(2) 基于annotation的配置方式
- 一.spring-core IoC container(3) 基于javaCode的配置方式
- Core Container
- Configuring Beans in the Spring IoC Container
- Spring核心技术--IoC container用法详解
- 【Spring Framework Reference 简记】—— IoC container and Beans(一)
- Laravel 4 IoC Container
- Laravel 4 IOC container
- MartinFowler: IOC, not IOC Container
- MartinFowler: IOC, not IOC Container
- 我的Session Bean Container实现(1)
- Container
- Container
- Container
- Container
- 设备驱动中的pinctrl(kernel-4.7)
- Android最佳性能实践(四)——布局优化技巧
- 深度探索QT窗口系统---几何篇1
- zmq 中的 zmq_init
- elasticsearch shield 认证的两种方式(http/java api)
- 一.spring-core IoC container(1) container概述和Bean基础
- 2.js按钮特效大全
- JAVA设计模式(二)工厂模式与观察者模式
- ORA-01861: 文字与格式字符串不匹配
- 绘画板的实现
- Spring - bean的作用域与生命周期
- ubuntu+kvm+vnc安装
- JavaScript MD5加密的方法
- zmq 中的 inproc