技术如果一段时间不练,再次捡起来就相当于一次重复学习,为加深理解和降低二次学习成本,spring系列大部分将转载
张开涛的博客(人家写的好而且全面),中间会加入一些自己的理解和总结。
说起spring,就会想起控制反转和依赖注入,这也是Spring的灵魂所在,再有其他的,可能就是一堆的配置文件或难搞懂的注解了,概念性的东西,下面两句话就够了。
IoC 控制反转(IoC容器控制对象) :IOC不是一种技术,而是一种思想,ioc容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
新建Dynamic web Project,拷入如下jar包:
=============================分界线========================================
IoC容器的代表就是org.springframework.beans包中的 BeanFactory接口,BeanFactory接口提供了IoC容器最基本功能;而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与Spring AOP集成、国际化处理、事件传播及提供不同层次的context实现 (如针对web应用的WebApplicationContext)。
容器实现一览(读取配置文件的几种方法):
- XmlBeanFactory:BeanFactory实现,通过了基本的IoC容器功能,课程classpath或文件系统等获取资源
1 File file=new File("fileSystemConfig.xml");
Resource resource=new FileSystemResource(file);
BeanFactory beanFactory=new XmlBeanFactory(resource);
2 Resource resource=new ClassPathResource("classpath.xml");
BeanFactory beanFactory=new XmlBeanFactory(resource);
- ClassPathXmlApplicationContext: ApplicationContext实现,从classpath获取配置文件
BeanFactory beanFactory=new ClassPathXmlApplicationContext("classpath.xml");
- FileSystemXmlApplicationContext: AplicationContext实现,从文件系统中获取配置文件
BeanFactory beanFactory=new FileSystemXmlApplicationContext("fileSsytemConfig.xml");
简单说, BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 则增加了更多支持企业级功能支持。ApplicationContext完全继承BeanFactory,因而BeanFactory所具有的语义也适用于ApplicationContext。
总结以上:读取配置文件其实就两种!分别是classpath(类路径)和文件系统中获取,而最常用的是从classpath下获取(上边标红),其他了解即可!
下面来看bean的id指定方式
1 不指定id,只配置必须的全限定类名,由IoC容器为其生成一个标识,客户端必须通过接口“T getBean(Class<T> requiredType)”来获取Bean
BeanFactory beanFactory=new ClassPathXmlApplicationContext("namingBean1.xml");
HelloApi hellApi=beanFactory.getBean(HelloApi.class);
hello.sayHello();
2 指定id,必须在IoC容器中 唯一
<bean id=” bean” class=“com.helloworld.HelloImpl”/>
<bean name=“bean” class=” com.hello.HelloImpl”/>
<bean id=”bean1”name=”alias1” class=“com.hello.HelloImpl”/>
<!-- 如果id和name一样,IoC容器能检测到,并消除冲突 -->
<bean id="bean3" name="bean3" class="com.hello.HelloImpl"/>
<bean name=” bean1;alias11,alias12;alias13 alias14” class="com.hello.HelloImpl"/>
<!-- 当指定id时,name指定的标识符全部为别名 -->
<bean id="bean2" name="alias21;alias22" class="com.hello.HelloImpl"/>
Bean命名约定:Bean的命名遵循XML命名规范,但最好符合Java命名规范,由“字母、数字、下划线组成“,而且应该养成一个良好的命名习惯, 比如采用“驼峰式”,即第一个单词首字母开始,从第二个单词开始首字母大写开始,这样可以增加可读性。
总结:“茴香豆”的“茴”字写法虽多,但都是一个意思。id和name都能找到bean,都不能有重复,且都遵循一定命名规则(不能以数字符号打头,尽量使用字母下划线数字组合,写其他的纯自找不自在)。
2、使用静态工厂方式实例化Bean,使用这种方式除了指定必须的class属性,还要指定factory-method属性来指定实例化Bean的方法,而且使用静态工厂方法也允许指定方法参数,spring IoC容器将调用此属性指定的方法来获取Bean
说起spring,就会想起控制反转和依赖注入,这也是Spring的灵魂所在,再有其他的,可能就是一堆的配置文件或难搞懂的注解了,概念性的东西,下面两句话就够了。
IoC 控制反转(IoC容器控制对象) :IOC不是一种技术,而是一种思想,ioc容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
DI(Dependency):依赖注入,通过配置,无需代码而指定目标需要的资源,完成自身的业务逻辑,而无需关心具体资源来自何处,由谁实现。
HelloWorld,来体会spring的便捷之处
Spring下载地址: http://repo.spring.io/release/org/springframework/spring/新建Dynamic web Project,拷入如下jar包:
src下新建目录com.hello,这里不考虑分包,接下来几个文件都放在该目录下。
public interface HelloApi {
public void say();
}
public class HelloImpl implements HelloApi {
@Override
public void say() {
System.out.println("hello world!");
}
}
项目右键->build path->java Build path->libraries->add library,加入JUnit 4包:
public class HelloTest {
@Test
public void testHelloWorld(){
//1、读取配置文件实例化一个IoC容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("/com/hello/bean.xml");
//2、从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现”
HelloApi api=ctx.getBean("hello",HelloApi.class);
//3、执行业务逻辑
api.say();
}
}
新建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-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- id 表示你这个组件的名字,class表示组件类 -->
<bean id="hello" class="com.hello.HelloImpl"></bean>
</beans>
部署完成后,到这里一个简单的helloworld就完成了。
=============================分界线========================================
IoC容器的代表就是org.springframework.beans包中的 BeanFactory接口,BeanFactory接口提供了IoC容器最基本功能;而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与Spring AOP集成、国际化处理、事件传播及提供不同层次的context实现 (如针对web应用的WebApplicationContext)。
容器实现一览(读取配置文件的几种方法):
- XmlBeanFactory:BeanFactory实现,通过了基本的IoC容器功能,课程classpath或文件系统等获取资源
1 File file=new File("fileSystemConfig.xml");
Resource resource=new FileSystemResource(file);
BeanFactory beanFactory=new XmlBeanFactory(resource);
2 Resource resource=new ClassPathResource("classpath.xml");
BeanFactory beanFactory=new XmlBeanFactory(resource);
- ClassPathXmlApplicationContext: ApplicationContext实现,从classpath获取配置文件
BeanFactory beanFactory=new ClassPathXmlApplicationContext("classpath.xml");
- FileSystemXmlApplicationContext: AplicationContext实现,从文件系统中获取配置文件
BeanFactory beanFactory=new FileSystemXmlApplicationContext("fileSsytemConfig.xml");
简单说, BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 则增加了更多支持企业级功能支持。ApplicationContext完全继承BeanFactory,因而BeanFactory所具有的语义也适用于ApplicationContext。
总结以上:读取配置文件其实就两种!分别是classpath(类路径)和文件系统中获取,而最常用的是从classpath下获取(上边标红),其他了解即可!
xml配置的结构
一般配置文件结构如下: <beans>
<!--导入其他配置文件的bean定义,可以放在beans下的任意位置,没有顺序关系,当然也可以把这些配置文件构造为一个数组
(new String[] {“config1.xml”, config2.xml})传给ApplicationContext实现进行加载多个配置文件
-->
<import resource=”resource1.xml”/>
<bean id=”bean1”class=””></bean>
<bean id=”bean2”class=””></bean>
<bean name=”bean2”class=””></bean>
<!--alias定义bean别名-->
<alias alias="bean3" name="bean2"/>
<import resource=”resource2.xml”/>
</beans>
bean命名 ------你知道“茴香豆”的“茴”字有几种写法吗?
每个Bean可以有一个或多个id(或称之为标识符或名字),在这里我们把第一个id称“标识符”,其余id叫做“别名”;这些id在IoC容器中必须唯一。下面来看bean的id指定方式
1 不指定id,只配置必须的全限定类名,由IoC容器为其生成一个标识,客户端必须通过接口“T getBean(Class<T> requiredType)”来获取Bean
BeanFactory beanFactory=new ClassPathXmlApplicationContext("namingBean1.xml");
HelloApi hellApi=beanFactory.getBean(HelloApi.class);
hello.sayHello();
2 指定id,必须在IoC容器中 唯一
<bean id=” bean” class=“com.helloworld.HelloImpl”/>
BeanFactory beanFactory=new ClassPathXmlApplicationContext("namingBean1.xml");
HelloApi hellApi=beanFactory.getBean("Bean",HelloApi.class);
hello.sayHello();
3 指定name,这样name就是“标识符”,必须在Ioc容器中
唯一;
<bean name=“bean” class=” com.hello.HelloImpl”/>
BeanFactory beanFactory=new ClassPathXmlApplicationContext("namingBean1.xml");
HelloApi hellApi=beanFactory.getBean("Bean",HelloApi.class);
hello.sayHello();
4 指定id和name,id就是标识符,而name就是别名,必须在Ioc容器中
唯一;
<bean id=”bean1”name=”alias1” class=“com.hello.HelloImpl”/>
<!-- 如果id和name一样,IoC容器能检测到,并消除冲突 -->
<bean id="bean3" name="bean3" class="com.hello.HelloImpl"/>
BeanFactory beanFactory = new ClassPathXmlApplicationContext("namingbean4.xml");
//根据id获取bean
HelloApi bean1 = beanFactory.getBean("bean1", HelloApi.class);
bean1.sayHello();
//根据别名获取bean
HelloApi bean2 = beanFactory.getBean("alias1", HelloApi.class);
bean2.sayHello();
//根据id获取bean
HelloApi bean3 = beanFactory.getBean("bean3", HelloApi.class);
bean3.sayHello();
String[] bean3Alias = beanFactory.getAliases("bean3");
//因此别名不能和id一样,如果一样则由IoC容器负责消除冲突
Assert.assertEquals(0, bean3Alias.length);
5 指定多个name,多个name用","、";"、""分割,第一个被用作标识符,其他的(alias1、alias2、alias3)是别名,所有标识符也必须在Ioc容器中唯一<bean name=” bean1;alias11,alias12;alias13 alias14” class="com.hello.HelloImpl"/>
<!-- 当指定id时,name指定的标识符全部为别名 -->
<bean id="bean2" name="alias21;alias22" class="com.hello.HelloImpl"/>
BeanFactory beanFactory = new ClassPathXmlApplicationContext("namingbean5.xml");
//1根据id获取bean
HelloApi bean1 = beanFactory.getBean("bean1", HelloApi.class);
bean1.sayHello();
//2根据别名获取bean
HelloApi alias11 = beanFactory.getBean("alias11", HelloApi.class);
alias11.sayHello();
//3验证确实是四个别名
String[] bean1Alias = beanFactory.getAliases("bean1");
System.out.println("=======namingbean5.xml bean1 别名========");
for(String alias : bean1Alias) {
System.out.println(alias);
}
Assert.assertEquals(4, bean1Alias.length);
//根据id获取bean
HelloApi bean2 = beanFactory.getBean("bean2", HelloApi.class);
bean2.sayHello();
//2根据别名获取bean
HelloApi alias21 = beanFactory.getBean("alias21", HelloApi.class);
alias21.sayHello();
//验证确实是两个别名
String[] bean2Alias = beanFactory.getAliases("bean2");
System.out.println("=======namingbean5.xml bean2 别名========");
for(String alias : bean2Alias) {
System.out.println(alias);
}
Assert.assertEquals(2, bean2Alias.length);
从定义来看,name或id如果指定它们中的一个时都作为“标识符”,那为什么还要有id和name同时存在呢?这是因为当使用基于XML的 配置元数据时,在XML中id是一个真正的XML id属性,因此当其他的定义来引用这个id时就体现出id的好处了,可以利用XML解析器来验证引用的这个id是否存在,从而更早的发现是否引用了一个不存在的bean,而使用name,则可能要在真正使用bean时才能发现引用 一个不存在的bean。
Bean命名约定:Bean的命名遵循XML命名规范,但最好符合Java命名规范,由“字母、数字、下划线组成“,而且应该养成一个良好的命名习惯, 比如采用“驼峰式”,即第一个单词首字母开始,从第二个单词开始首字母大写开始,这样可以增加可读性。
总结:“茴香豆”的“茴”字写法虽多,但都是一个意思。id和name都能找到bean,都不能有重复,且都遵循一定命名规则(不能以数字符号打头,尽量使用字母下划线数字组合,写其他的纯自找不自在)。
实例化Bean
Spring IoC容器则需要根据Bean定义里的配置元数据使用反射机制来创建Bean。有3种方式:构造器,静态工厂,实例化工厂方法。
还是以上面helloword的例子来演示:
1.构造方法,在HelloApi中加入两个构造器,一个是默认的,一个是带参的
public class HelloImpl implements HelloApi {
private String msg;
public HelloImpl(){
this.msg="Hello World! construct";
}
public HelloImpl(String msg){
this.msg=msg;
}
@Override
public void say() {
System.out.println(msg);
}
}
<bean name="bean1" class="com.HelloImpl"/>
<!-- 指定构造器参数 -->
<constructor-arg index="0" value="Hello Spring!"/>
</bean>
2、使用静态工厂方式实例化Bean,使用这种方式除了指定必须的class属性,还要指定factory-method属性来指定实例化Bean的方法,而且使用静态工厂方法也允许指定方法参数,spring IoC容器将调用此属性指定的方法来获取Bean
public class HelloApiStaticFactory {
//工厂方法
public static HelloApi newInstance(String message) {
//返回需要的Bean实例
return new HelloImpl2(message);
}
}
静态工程写完了,下面配置bean.xml,注意要指定factory-method
<!-- 使用静态工厂方法 -->
<bean id="bean2" class="com.hello.HelloApiStaticFactory" factory-method="newInstance">
<constructor-arg index="0" value="Hello Spring!"/>
</bean>
3、使用实例工厂方法实例化Bean,使用这种方式不能指定class属性,此时必须使用factory-bean属性来指定工厂Bean,factory-method属性指定实例化Bean的方法,而且使用实例工厂方法允许指定方法参数,方式和使用构造器方式一样,配置如下:
public class HelloApiInstanceFactory {
public HelloApi newInstance(String message) {
return new HelloImpl(message);
}
}
<!-- 1、定义实例工厂Bean -->
<bean id="beanInstanceFactory" class="com.hello.HelloApiInstanceFactory" />
<!-- 2、使用实例工厂Bean创建Bean -->
<bean id="bean3" factory-bean="beanInstanceFactory"
factory-method="newInstance">
<constructor-arg index="0" value="Hello Spring!"></constructor-arg>
</bean>
这三种方式只是配置不一样,从获取方式看完全一样,没有任何不同。这也是Spring IoC的魅力,Spring IoC帮你创建Bean,我们只管使用就可以了。