主要内容
- IOC概念和设计思想
- java反射技术
- BeanFactory、ApplicationContext以及WebApplicationContext基础接口
- Bean的生命周期
IOC
IOC被定义称作为控制反转,主要表示控制类的实例化,通过Spring容器(即Bean配置来进行控制)反转表示控制权权交给Spring处理,通过java反射技术来进行操控。
说到实际,IOC就是java反射的绝对应用。
IOC有两种注入方式:
- 构造函数注入
- 属性方法注入
-接口注入
为什么需要三种构造方式呢?有一种不就够了吗,有构造参数注入不就可以了吗?这是因为并不是每次注入都需要产生特定的角色,属性注入更加灵活,可以更随意。
spring的三种注入方式
2018-07-29
spring的依赖注入分为三种方式
1.构造器注入
2.setter注入
3.接口注入
构造器注入和setter注入是依赖注入的两种主要方式,接口注入是指从别的地方注入的方式。(通过在xml中描述,实现注入)
一、构造器注入
构造器注入依赖于构造方法的实现,----------构造方法可以是有参数的,也可以是无参数的 。
在没有spring之前,我们在大多数情况下,我们都是通过构造方法来创建类对象,Spring可以采用反射的方式,通过构造方法来完成注入,这就是构造方法的原理。
1.引入spring的支持
2.通过描述具体的类,构造方法和其中的参数,这样spring就可以通过相应的信息用反射的方式创建对象。
3.在test文件中加载spring配置文件的方法
String configLocation ="applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
Role role = context.getBean("role", Role.class);
在spring中一切的资源都是bean。
二、spring中最主流的注入方式:setter注入
setter注入利用JAVA Bean规范所定
注意: 构造器注入是通过构造方法注入,setter注入是通过setter方法注入
首先将构造方法设置为无参的构造方法,然后利用setter注入为其设置新的值,这也是通过java的反射技术得以实现的
注意:构造器注入和setter注入都是通过java的反射技术得以实现的。
<!-- 下面是setter注入,需要一个无参的构造方法 -->
<bean id="role1" class="com.pojo.Role" >
<property name="id" value="124"></property>
<property name="name" value="张三"></property>
<property name="age" value="2324"></property>
</bean>
三、spring依赖注入的第三种方式:接口注入
有时候资源并非来自于自身的系统,而是来自于外界,比如说数据库连接资源完全可以在Tomcat下配置,然后通过JNDI的方式去获取它,这样的数据库连接资源就属于开发工程外的资源。
启动IOC容器方式
- 通过BeanFactory启动IOC容器
BeanFactory类是Spring框架下最核心的接口,它提供了高级的IOC配置机制。我们可以使用下面的XmlBeanDefinitionReader和DefaultListableBeanFactory类启动IOC容器。
- 通过ApplicationContext类启动IOC容器
ApplicationContext类继承了BeanFactory类,实现了更多面向应用的功能。
我们就在上例的基础上,在test/java目录下,使用TestNG框架再编写一个ApplicationContextTest类。同样可以实现像上面两种加载XML文件启动IOC容器的方法,此外,ApplicatioinContext类还可以通过类注解的方式加载Bean启动IOC容器。
- 通过WebApplicationContext类启动IOC容器
WebApplicationContext类继承了ApplicationContext类,专门用于Web应用。启动方式也是通过Web容器启动,实现IOC容器的启动。不能简单通过Java代码实现启动。
在webapp/WEB-INF下的web.xml中定义ContextLoaderListener监听Web容器的启动,然后定义contextConfigLocation获得Spring框架的Bean配置文件。
然后在web.xml文件中,再定义一个Servlet,定义它的属性load-on-startup为1,表示在Web容器和Spring框架的IOC容器启动之后自启动,得到WebApplicationContext类的实例,就可以得到Bean实例了。
web.xml文件如下图所示
在com.czuaphe.webtest包下,编写SpringBeanServlet类,重写Servlet的init()方法,得到WebApplicationContext类的实例。
编写了三种IOC容器的启动方式,在非Web应用下,使用ApplicationContext启动IOC容器就已经足够使用,在Web应用下,就必须在web.xml文件中配置WebApplicationContext的启动。让Web容器启动时IOC容器也启动。BeanFactory类启动IOC容器一般不常用。
java反射机制
测试类:
public class AppTest{
private String name;
private int age;
private String address;
public AppTest() {
System.out.println("无参构造函数--");
}
public AppTest(String name,int age) {
System.out.println("有参构造函数**");
}
public void message(String name,int age,String address){
System.out.println("姓名:"+name+"##"+"年龄:"+age+"##"+"地址:"+address);
}
}
反射获取测试类:
public class MyTest{
public static void main(String[] arg) throws Exception {
ClassLoader loader=Thread.currentThread().getContextClassLoader();
Class clazz=loader.loadClass("com.spring.AppTest");
//Class clazz=Class.forName("com.spring.AppTest");
AppTest appTest=(AppTest) clazz.newInstance();
Method m=clazz.getMethod("message", String.class,int.class,String.class);
m.invoke(appTest, "zhangsan",17,"beijng");
}
}
结果:
无参构造函数--
姓名:zhangsan##年龄:17##地址:beijng
类装载器ClassLoader
类装载器工作机制:
类的装载器就是寻找类的字节码文件并构造出类在JVM内部表示对象组件,在java中,类装载器把一个类装入JVM中,需要经过一下步骤:
- (1)装载:查找和导入Class文件。
- (2)链接:执行校验、准备和解析步骤,其中解析步骤是可以选择的。
- -校验:检查载入Class文件的正确性。
- -准备:给类的静态变量分配存储空间。
- -解析:将符号引用转换为直接引用。
- (3)初始化:对类的静态变量、静态代码块执行初始化工作。
资源访问利器
资源抽象接口
JDK所提供的资源的类(如java.net.URL,File等),并不能很好的满足各种底层资源访问需求,比如缺少从类路径或者Web容器上下文中获取资源的操作类。
于是Spring设计了一个Resource接口,它为应用程序提供了更强的底层资源访问能力。该接口拥有对应不同资源的实现。
Resource主要方法实现:
boolean exists():资源是否存在
boolean isOpen():资源是否打开
URL getURL() throws IOException:如果底层资源可以表示成URL,则该方法返回对应的URL对象。
File getFile() throws IOException:如果底层资源对应一个文件,则该方法返回对应的File对象。
InputStream getInputStream() throws IOException:返回资源对应的输入流。
Resource在起着不可或缺的作用,Spring框架使用Resource装载各种资源,包括配置文件资源,国际化属性资源等。
- WritableResource:可写资源接口,两个实现类,FileSystemResource和PathResource。
- ByteArrayResource:二进制数组表示资源,二进制数组资源可以在内存中通过程序构造。
- ClassPathResource:类路径下的资源,资源以相对于类路径的方式表示,
资源加载
为了访问不同的资源必须使用的不同的Resource实现类,还是比较麻烦的。是否可以在不显式使用Resource实现类的情况下,仅通过资源地址的特殊标识就可以访问相应的资源呢?Spring提供了一个强大的资源加载机制,不但能够通过
*后续继续更新
BeanFactory和ApplicationContext
Spring通过一个配置文件描述Bean及Bean之间的关系,利用java语言的反射功能实例化Bean,并建立Bean之间的依赖关系,Spring的IOC容器在完成这些底层的工作基础上,还提供了Bean的实例缓存、声明周期管理、Bean的实例代理、事件发布、资源装载等高级服务。
Bean工厂(com.springframework.beans.factory.BeanFactory)是Spring框架最核心的接口,它提供了高级IOC配置机制,BeanFactory使管理不同类型的java对象成为可能。
应用上下文(com.springframework.context.ApplicationContext)建立在BeanFactory的基础之上,提供了更多面向应用的功能,它提供了国际化支持和框架事件体系,更易于创建实际应用。
我们一般称BeanFactory为IOC容器,而称ApplicationContext为应用上下文。
对于二者的用途,我们可以进行简单的划分:BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都可以直接使用ApplicationContext而非底层的BeanFactory。
BeanFactory
Beanfactory是一个类工厂,但和传统的类工厂不同,传统的类工厂仅负责构造一个或几个类的实例,而BeanFactory是类的通用工厂,它可以创建并管理各种类对象,这些被创建和管理的对象本身没有什么特别之处,仅仅是一个POJO,Spring称这些被创建和管理的java对象为Bean。我们知道javaBean是要满足一定规范的,如必须提供一个默认不带参的构造函数,不依赖于某一特定的容器等,但Spring中所说的Bean比javaBean更宽泛一些,所以可以被Spring容器实例化并管理的Java类都可以成为Bean。
BeanFactory的体系结构
Spring为BeanFactory提供了多种实现,最常用的是XmlBeanFactory,但现在已经废弃,建议使用XmlBeanDefinitionRead、DefaultListableBeanFactory代替。
BeanFactory接口位于类结构树的顶端,它最主要的方法就是getBean(String beanName),该方法从容器中,返回特定名称的Bean。
实例:
<bean id="appTest" class="com.spring.AppTest"
p:name="cui"
p:age="18"
p:address="beijing" />
public class AppTest{
private String name;
private int age;
private String address;
public AppTest() {
System.out.println("无参构造函数--");
}
public AppTest(String name,int age) {
System.out.println("有参构造函数**");
}
public void message(String name,int age,String address){
System.out.println("姓名:"+name+"##"+"年龄:"+age+"##"+"地址:"+address);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getString() {
// TODO Auto-generated method stub
return this.name+" "+this.age+" "+this.address;
}
}
/**
* 测试
*/
public class MyTest{
public static void main(String[] arg) throws Exception {
ResourcePatternResolver resolver=new PathMatchingResourcePatternResolver();
Resource resource=resolver.getResource("classpath:applicationContext.xml");
System.out.println(resource.getURL());
DefaultListableBeanFactory dBeanFactory=new DefaultListableBeanFactory();
XmlBeanDefinitionReader xReader=new XmlBeanDefinitionReader(dBeanFactory);
xReader.loadBeanDefinitions(resource);
System.out.println("init BeanFactory");
AppTest app=(AppTest) dBeanFactory.getBean("appTest");
String s=app.getString();
System.out.println(s);
}
}
结果:
file:/D:/EclipseWorkSpace/spring/target/classes/applicationContext.xml
init BeanFactory
无参构造函数--
cui 18 beijing
XmlBeanDefinitionReader通过Resource装载Spring配置信息并启动IOC容器,然后就可以通过
BeanFactory#getBean(beanName)方法从IOC容器获取Bean。通过BeanFactory启动IOC容器时,并
不会初始化配置文件中定义Bean,初始化动作发生在第一次调用时,对于单例的Bean来说,BeanFactory会
缓存Bean的实例,所以第二次使用getBean()获取Bean时,将直接从IOC容器的缓存中获取Bean实例。
Spring在DefaultSingletonBeanRegistry类中提供了一个用于缓存单实例Bean的缓存器,它是一个用
HashMap实现的缓存器,单实例Bean以beanName为键保存在这个HashMap中。
需要注意的是:在初始化BeanFactory时,必须为其提供一种日志框架,我们使用Log4J,即在类路径下
提供Log4j配置文件,这样启动Spring容器才不会报错。
ApplicationContext介绍
如果说BeanFactory是Spring的心脏,那么ApplicationContext就是完整的身躯了。ApplicationContext由BeanFactory派生而来,提供了更多面向实际的功能,在BeanFactory中,很多功能以编程的方式实现,而在ApplicationContext中则可以通过配置的方式实现。
1.ApplicationContext类体系结构:
ApplicationContext的主要实现类是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext前者默认从类路径加载配置文件,后者默认从文件系统中装载配置文件。
ApplicationContext继承了HierarchicalBeanFactory和ListableBeanFactory接口,在此基础上,还通过其他接口拓展了BeanFactory的功能。
- ApplicationEventPublisher:让容器拥有发布上下文事件的功能,包括容器的启动事件和关闭事件等。实现了ApplicationListener事件监听接口的Bean可以接收到容器事件,并对时间进行响应处理,在ApplicationContext抽象实现类AbstractApplicationContext中存在一个ApplicationEventMulticaster,它负责保存所有的监听器。以便在容器产生上下文事件时,通知这些事件监听者。
- MessageSource:为应用提供i18n国际化消息访问功能。
- ResourcePatternResolver:所有的ApplicationContext实现类都实现了类似于PathMatchingResourcePatternResolver的功能。可以通过带前缀的Ant风格的资源文件路径装载Spring配置文件。
- LifeCycle:该接口提供了start()和stop()两个方法,主要控制异步处理过程,再具体使用中,该接口同时被ApplicationContext实现和具体的Bean实现。ApplicationContext会将start/stop的信息传递给容器中,所有实现了该接口的Bean已达到管理和控制JMX、任务调度目的。