Spring框架
一、Spring框架概述
1、Spring是一个service层的框架,可以整合许多其他框架进行工作。
2、Spring的主要技术:
(1)IOC(DI)
控制反转(依赖注入):低耦合——代码分离、便于代码复用
(2)AOP
面向切面编程:高内聚——结构清晰、便于开发维护
二、控制反转(低耦合)
由Spring框架管理对象创建和生命周期的机制称为控制反转
1、创建Spring的project
2、导入jar包
3、创建Spring的xml配置文件
4、配置Person类
id | 标识配置的这个bean的类名 |
class | 标识配置这个类的全路径 |
<bean id="person" class="cn.tedu.domain.Person">
5、Spring实现IOC的底层原理
@Test
public void test02(){
//1、初始化容器:发现配置文件开始解析Spring配置文件
ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
//2、通过Spring容器创建对象,获取person类
Person person =(Person)context.getBean("person");
person.eat();
person.sleep();
//3、关闭Spring容器
//ClassPathXmlApplicationContext有close();ApplicationContext没有close()
((ClassPathXmlApplicationContext)context).close();
}
推论一:可以多次获取同一个id的bean,获取到的值相同
推论二:不能配置多个id相同的bean
推论三:可以配置多个class相同但id不同的bean
6、获取对象的方式:
(1)通过id获取对象(常用)
Person p = (Person)context.getBean("person");//cn.tedu.domain.Person@65e
找到唯一 | 返回对象 |
找不到 | NoSuchBeanDefinitionException |
找到多个 | 不可能,id是唯一标识 |
(2)通过class获取对象
Person p1 = context.getBean(Person.class);
找到唯一 | 返回对象 |
找不到 | 再找该类型的子孙类型的bean,找到则返回子孙对象 |
都找不到 | NoSuchBeanDefinitionException |
找到多个 | 有可能找到多个,抛出异常NoUniqueBeanDefinitionException |
(3)指定id别名
name:指定对应的bean的id,alias指定新id
<alias name="person" alias="person2"></alias>
7、创建Spring对象
Spring创建对象的本质:通过类的无参构造器来创建对象。
(1)无参构造
<bean id="person" class="cn.tedu.domain.Person"></bean>
实现原理:在Spring容器初始化时,通过上配置的class属性反射得到字节码文件,在通过newInstance()创建实例对象。这种创建方法的类中只能有无参构造方法,否则无法使用反射。
(2)有参构造
实现原理:通过配置bean的参数,实现控制Spring容器通过指定的构造器创建对象,而不是通过默认的无参构造器
index | 三者不需要都设置,没有歧义即可 有参构造的第几个参数,0开始 |
name | 参数名 |
type | 参数类型 |
value | 二选一 赋予的具体指(基本数据类型或者String类型) |
ref | 赋予值(引用数据类型) |
配置文件
<bean id="person2" class="cn.tedu.domain.Person2">
<constructor-arg index="0" name="name" type="java.lang.String" value="lili"></constructor-arg>
<constructor-arg index="1" name="age" type="int" value="10"></constructor-arg>
</bean>
Person2
public Person2(String name,int age){
System.out.println("person2,name:"+name+",age:"+age);
}
Test
//有参构造创建对象
@Test
public void test05(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person2 p = (Person2)context.getBean("person2");
System.out.println(p);
((ClassPathXmlApplicationContext)context).close();
}
(3)静态工厂
实现原理:因为要使用指定的静态方法来实例化对象,就得将静态工厂类中的无参构造方法私有化。
通过工厂创建对象:如果创建出来的对象需要经过若干设置后才能使用,spring也支持通过工厂创建bean。
工厂设计模式:就是通过一个工厂类将创建对象的细节封装起来,之后通过工厂创建对象,简化创建对象的过程。
NetConn.java
public class NetConn {//实现连接好网络后查询数据的功能
public void load(){ System.out.println("加载配置文件..."); }
public void ping(){ System.out.println("测试网络..."); }
public void conn(){System.out.println("连接网络...");}
public void login(){System.out.println("登录...");}
public void sendData(){System.out.println("发送数据..."); }
}
NetConnStaticFactory.java
public class NetConnStaticFactory {//创建工厂类,将网络连接和登录操作封装起来
private NetConnStaticFactory(){}//私有化无参构造方法
public static NetConn getNetConn(){//创建NetConn类的对象
NetConn nc = new NetConn();//通过nc调用这些方法,完成方法的封装
nc.load();
nc.ping();
nc.login();
return nc;
}
}
applicationContext.xml
<!-- 配置静态工厂方法目的:通过指定的静态工厂方法创建对象
此时已经发生了操作 NetConn conn=NetConnStaticFactory.getNetConn();-->
<bean id="nc" class="cn.tedu.domain.NetConnStaticFactory" factory-method="getNetConn"></bean>
TestDemo.java
public void test01(){
//前提假设:使用NetConn类的对象直接调用sendData(),不需要连接检查操作
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean:拿到Spring容器创建好的实例对象conn
//nc的数据类型需是NetConn,后续才能使用该对象直接调用sendData()方法
NetConn nc =(NetConn) context.getBean("nc");
nc.sendData();
//关闭Spring容器
((ClassPathXmlApplicationContext)context).close();
}
(4)实例工厂
实现原理:实例工厂中的方法不是静态的,所以不能直接调用自定义的工厂方法来实例化对象。(因为.xml先于.java文件加载)所以先配置工厂对象的bean,底层创建出一个工厂对象后,再配置自定义工厂方法就可以实例化对象。
NetConnInstanceFactory.java
public class NetConnInstanceFactory {
private NetConnInstanceFactory(){}//私有化无参构造方法
public NetConn getNetConn(){//创建非静态工厂方法
NetConn nc = new NetConn();
nc.load();
nc.ping();
nc.login();
return nc;
}
}
applicationConext.xml
<bean id="NetConnInstanceFactory" class="cn.tedu.domain.NetConnInstanceFactory"></bean>
<!-- 相当于给netConn也准备了一个实例对象-->
<bean id="netConn" factory-bean="NetConnInstanceFactory" factory-method="getNetConn"></bean>
TestDemo.java
public void test02(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取id为NetConn的bean标签(相当于获取实例化好的NetConn对象)
NetConn netConn = (NetConn) context.getBean("netConn");
netConn.sendData();
((ClassPathXmlApplicationContext)context).close();
}
(5)Spring工厂
实现原理:让普通工厂实现FactoryBean接口;在工厂类中实现生产对象的创建;然后在.xml文件中配置bean-id、bean-class,就能实例化对象。
NetSpringFactory.java
public class NetConnSpringFactory implements FactoryBean<NetConn> {
@Override //创建生产目标
public NetConn getObject() throws Exception {
NetConn nc = new NetConn();
nc.load();
nc.ping();
nc.conn();
nc.login();
return nc;
}
@Override //获取目标对象的类型
public Class<?> getObjectType() { return NetConn.class; }
@Override//控制生产目标对象是否是单例
public boolean isSingleton() {return false;}
}
applicationContext.xml
<bean id="nc" class="cn.tedu.domain.NetConnSpringFactory"></bean>
TestDemo.java
@Test
public void test03(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
NetConn nc = (NetConn)context.getBean("nc");
nc.sendData();
((ClassPathXmlApplicationContext)context).close();
}
(6)单例、多例
(7)懒加载机制
在单例标签上配置lazy-init=true会设置为懒加载模式,在此模式下不会在容器初始化时创建bean对象,而是在第一次使用对象时创建,从而减少了容器启动的时间和空间的消耗。
懒加载只对单例bean标签生效(懒加载本身就是多例);懒加载只是延后了对象创建的时机,对象仍然是单例的。
全局
局部
<bean id="person" class="cn.tedu.domain.Person" lazy-init="false"></bean>
同时设置则就近生效局部的
(8)Spring实现配置自定义的初始化、销毁方法
<bean id="nc" class="cn.tedu.domain.DBUtils" init-method="init" destroy-method="destroy"></bean>
NetConn.java
public class NetConn { //实现连接好网络后查询数据的功能
public void init(){System.out.println("连接数据库...");}
public void sendData(){
System.out.println("发送数据...");
}
public void destroy(){System.out.println("断开数据库连接..");}
}
TestDemo.java
@Test
public void test04(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
NetConn nc = (NetConn)context.getBean("nc");
nc.sendData();
((ClassPathXmlApplicationContext)context).close();
}