Spring概述
- spring是一个轻量级的开源的JavaEE框架,目的是解决企业级应用开发的复杂性
- spring有两个核心部分:IOC(反转控制)和AOP(面向切面编程),IOC作用是将创建对象的过程交给spring来管理;AOP作用是不需要修改源代码就能进行功能的添加。
Spring入门案例

步骤:
-
首先创建一个基本的java工程
-
然后创建lib文件夹,放置五个jar包(beans、context、core、expression、commons-logging)

-
然后引用上步的jar包

-
创建一个实体类

-
创建一个spring配置文件(xml格式),并配置想要创建的实体类

配置文件中在beans节点下写一个bean标签,给标签写一个id属性和class属性,这个id作用是在创建对应实体类对象的时候进行获取该节点描述的。class属性是指定该实体类的类文件路径。 -
写一个测试类,用来导入配置,创建实例,代用实例方法

//加载spring配置
ApplicationContext context=new ClassPathXmlApplicationContext("spring_demo.xml");
//获取bean实例
User user= context.getBean("user", User.class);
//调用实例的方法
user.show();
什么是IOC
IOC全称inversion if control(反转控制),它是面向对象对象编程中的一种设计原则,目的就是降低耦合度。假如有class1和class2两个类,如果我想在class1中调用class2的一个实例方法,那么就需要在class1中new一个class2的实例,有了IOC之后就不需要在class1中创建class2的实例来实现了,创建class2实例和调用实例成员的过程交给spring的IOC来处理,这样就降低了代码的耦合度。
IOC基本原理
实现IOC的三个技术:(1)xml解析 (2)工厂模式 ,工厂模式简单理解就是你想要什么我就给你返回什么(3)反射
- IOC实现过程:
1.在xml中配置实体类的bean节点
<bean id="user" class="com.company.demo.User"></bean>
2.解析xml文件中的属性值,通过反射创建实例,通过工厂模式返回实例
//创建一个User工厂类
public class UserFactory() {
public static User getUserInstance() {
//解析xml,拿到bean节点中的class属性值
String classValue = bean节点中的class属性值;
//通过反射创建实例
Class clazz = Class.forName(classValue);
return (User) clazz.newInstance();
}
}
IOC容器的两个核心接口
从IOC的基本原理来看,IOC的底层还是工厂。IOC容器中有两个核心的接口:Beanfactory和ApplicationContext,这两个接口的作用是一样的,都是spring中通过读取bean配置文件来创建对象的。可以将ApplicationContext看成是继承自BeanFactory的接口,但是二者还是有不同的地方:
- BeanFactory:这个接口是spring内部来使用的,不提供给开发人员调用,它在读取配置文件的时候并没有创建对象,而是在适用对象的时候才创建。
//加载spring配置,在读取配置文件的时候并没有创建对象
BeanFactory context=new ClassPathXmlApplicationContext("spring_demo.xml");
//获取bean实例,在调用的时候才创建
User user= context.getBean("user", User.class);
- ApplicationContext::这个接口继承自BeanFactory,所以功能比BeanFactory更强大,区别是这个接口在读取配置文件的时候就已经创建了对象。
//加载spring配置,此时就已经创建了对象
ApplicationContext context=new ClassPathXmlApplicationContext("spring_demo.xml");
//获取bean实例
User user= context.getBean("user", User.class);
ApplicationContext接口的两个实现类
FileSystemXmlApplicationContext(“这个填xml文件在文件系统中的绝对路径”)
ClassPathXmlApplicationContext(“这个填xml文件相对于src目录的路径”)
IOC进行Bean管理
- Bean管理包括两个方面:(1)通过spring创建对象(2)通过spring进行属性注入,也叫作依赖注入(DI),IOC和DI之间的关系可以理解为DI是IOC的一种实现方式。
- 创建对象和注入属性均可通过xml方式和注解方式进行操作。 通过xml方式进行创建对象上面已经说过,下面是通过xml方式进行注入属性:
1.通过set方式进行属性注入
(1)首先要在实体类中声明属性名称,写好set方法
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
//show方法
public void show() {
System.out.println(this.name);
}
}
(2)在spring配置文件中配置bean节点,然后再配置属性节点
<bean id="user" class="com.company.demo.User">
<property name="name" value="张三"></property>
</bean>
(3)加载配置文件,程序在加载配置文件的同时,就创建了对象,在完成创建对象的基础上,进行依赖注入
public static void main(String[] args) {
//加载spring配置,此时就已经创建了对象
ApplicationContext context=new ClassPathXmlApplicationContext("spring_demo.xml");
//获取bean实例
User user= context.getBean("user", User.class);
//调用实例的方法
user.show();
}
注意:上面这种方式在实例化对象时是默认调用这个类的“无参构造函数”来实例化的,所以此时类中必须有一个默认的的无参构造或者自己手写一个无参构造,否则报错
2.通过“有参构造函数”方式进行属性注入
(1)声明类,声明属性,声明一个有参构造函数
public class User {
private String name;
//声明一个有参构造函数
public User(String name) {
this.name = name;
}
//show方法
public void show() {
System.out.println(this.name);
}
}
(2)配置bean节点
<bean id="user" class="com.company.demo.User">
<constructor-arg name="name" value="张三"></constructor-arg>
</bean>
(3)加载spring配置文件,通过spring创建对象
//加载spring配置,此时就已经创建了对象
ApplicationContext context=new ClassPathXmlApplicationContext("spring_demo.xml");
//获取bean实例
User user= context.getBean("user", User.class);
//调用实例的方法
user.show();
Xml注入其他类型属性
- 字面量
(1) 注入null值
<!--属性值为null-->
<property name="name">
<null/>
</property>
(2)注入特殊符号
<!--属性值为特殊符号-->
<property name="name">
<value>
<![CDATA[特殊符号]]>
</value>
</property>
(3)注入对象类型属性
(4)注入数组或集合类型属性
对象类型属性注入——外部bean和内部bean
当一个类的属性是对象类型时,此时注入属性就可以通过外部bean或内部bean的方式注入,例如在service层调用dao层:
外部Bean写法:通过ref属性引入另一个bean
<bean id="user_dao" class="com.company.demo.dao.UserDaoImpl"></bean>
<bean id="user_service" class="com.company.demo.service.UserServiceImpl">
<!--注入外部bean时需要用ref属性-->
<property name="user_dao" ref="user_dao"></property>
</bean>
内部Bean写法:不需要写ref属性,直接将另一个bean对象写在property标签中
<bean id="user_service" class="com.company.demo.service.UserServiceImpl">
<property name="user_dao" >
<bean id="user_dao" class="com.company.demo.dao.UserDaoImpl"></bean>
</property>
</bean>
数组和集合类型属性注入(Array、List、Set、Map)
public class Stu {
private String[] course1;
private List<String> course2;
private Set<String> course3;
private Map<String,String> course4;
public void setCourse1(String[] course1) {
this.course1 = course1;
}
public void setCourse2(List<String> course2) {
this.course2 = course2;
}
public void setCourse3(Set<String> course3) {
this.course3 = course3;
}
public void setCourse4(Map<String, String> course4) {
this.course4 = course4;
}
//show方法
public void show(){
System.out.println("数组属性长度:"+this.course1.length);
System.out.println("List集合属性长度"+this.course2.size());
System.out.println("Set集合属性长度"+this.course3.size());
System.out.println("Map集合属性长度"+this.course4.size());
}
}
<bean id="stu" class="com.company.demo.bean.Stu">
<!--数组类型属性注入-->
<property name="course1">
<array>
<value>java1</value>
<value>php1</value>
</array>
</property>
<!--List集合类型属性注入-->
<property name="course2">
<list>
<value>java2</value>
<value>php2</value>
</list>
</property>
<!--Set集合类型属性注入-->
<property name="course3">
<set>
<value>java3</value>
<value>php3</value>
</set>
</property>
<!--Map集合类型属性注入-->
<property name="course4">
<map>
<entry key="JAVA4" value="java4"></entry>
<entry key="PHP4" value="php4"></entry>
</map>
</property>
</bean>
普通Bean和工厂Bean
- 普通Bean和工厂Bean的区别:普通Bean是我们在spring配置文件中配置的是什么类型的对象,就返回什么类型的对象。工厂Bean的特点是配置的对象的类型和返回的对象的类型可以不一样。
- 如何声明一个工厂Bean呢,首先声明一个工厂Bean的类,然后让它实现FactoryBean这个接口
public class MyFactoryBean implements FactoryBean<Stu> {
@Override
public Stu getObject() throws Exception {
Stu stu=new Stu();
return stu;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
<bean id="myBean" class="com.company.demo.factorybean.MyFactoryBean"></bean>
//加载配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
//获取对象
Stu stu= context.getBean("myBean",Stu.class);
//调用对象
stu.show();
很明显可以看出,在spring配置文件中我们配置的是MyFactoryBean类型的对象,但是返回的却是Stu类型的对象,这就是工厂Bean。
单实例和多实例
- 在spring配置中,对象默认是单实例,也就是每次通过spring获取的对象是同一个,内存地址是相同的。通过代码来验证下:
//加载配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
//获取对象
Stu stu1= context.getBean("stu",Stu.class);
Stu stu2= context.getBean("stu",Stu.class);
//输出对象内存地址,验证是多实例还是单实例
System.out.println(stu1);//com.company.demo.bean.Stu@11c9af63
System.out.println(stu2);//com.company.demo.bean.Stu@11c9af63
<bean id="stu" class="com.company.demo.bean.Stu"></bean>
由上可知,两个对象的内存地址是完全一样的,所以spring配置中Bean默认是返回单实例对象。
- 那么如何设置返回单实例或者多实例呢,很简单,只需要再spring配置文件的Bean节点中添加一个scope属性即可,该属性有两个值,分别代表返回单实例和多实例对象,singleton表示返回单实例对象,prototype表示返回多实例对象。下面我们来验证下多实例:
//加载配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
//获取对象
Stu stu1= context.getBean("stu",Stu.class);
Stu stu2= context.getBean("stu",Stu.class);
//输出对象内存地址,验证是多实例还是单实例
System.out.println(stu1);//com.company.demo.bean.Stu@5aebe890
System.out.println(stu2);//com.company.demo.bean.Stu@65d09a04
<bean id="stu" class="com.company.demo.bean.Stu" scope="prototype"></bean>
可以看出,当设置bean节点中scope属性为prototype时,两次返回的对象内存地址不同,因此是多实例。
- scope属性的singleton和prototype两个值的区别
(1)singleton是单实例,prototype是多实例
(2)如果设置为单实例,那么在spring配置文件加载的时候,单实例对象就被创建了;如果设置为多实例,在加载spring配置文件的时候,并没有进行对象的创建,而是在调用getBean()方法的时候进行多实例的创建。
Bean的生命周期
- 生命周期:
(1)创建Bean实例,默认调用无参的构造函数
(2)设置属性值和或者是引入外部Bean,调用set方法
(3)执行Bean里面初始化的方法,这个方法需要手动配置
(4)获取Bean,使用Bean
(5)销毁Bean实例,执行销毁的方法,这个方法需要配置
- 初始化和销毁方法声明和配置:


- 后置处理器
如果配置上后置处理器,那么整个生命周期就多了两步,这两步分别在初始化方法执行前后,这样就变成了七个关键点。
首先要声明一个后置处理器的类,让这个类实现BeanPostProcessor这个接口,实现它的两个方法,这两个方法会在Bean的初始化前后分别执行,分别是postProcessBeforeInitiallization()和postProcessAfterInitiallization()。
(1)创建Bean实例,默认调用无参的构造函数
(2)设置属性值和或者是引入外部Bean,调用set方法
(3)执行后置处理器的postProcessBeforeInitiallization()方法
(4)执行Bean里面初始化的方法,这个方法需要手动配置
(5)执行后置处理器的postProcessAfterInitiallization()方法
(6)获取Bean,使用Bean
(7)销毁Bean实例,执行销毁的方法,这个方法需要配置
声明后置处理器以及配置:
//声明一个后置处理器
public class BeanInitBeforeAndAfter implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//Bean初始化之前执行,返回创建的Bean实例
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//Bean初始化之后执行,返回创建的Bean实例
return bean;
}
}
<!-- spring识别到这个类实现了BeanPostProcessor这个接口,就会把它当做一个后置处理器,然后其他Bean实例就都有了初始化前后的两个过程-->
<bean id="beaninit" class="com.company.demo.bean.BeanInitBeforeAndAfter"></bean>
注意:spring识别到这个类实现了BeanPostProcessor这个接口,就会把它当做一个后置处理器,然后其他Bean实例就都有了初始化前后的两个过程
XML自动装配
- 什么是自动装配?
自动装配就是在spring配置文件中进行bean的配置的时候,不需要我们手动写属性标签了,Bean标签的autowire属性可实现自动装配,spring识别到这个属性后,会自动帮助我们进行属性注入(引入外部Bean)
- autowire属性的两个属性值
(1)byName:通过识别属性名称进行自动装配
<!--根据属性名称进行自动装配,切记引入的外部bean的id一定要和本类的属性名称一样,spring才能进行自动装配-->
<bean id="emp" class="com.company.demo.aotuwire.Emp" autowire="byName"></bean>
<bean id="dept" class="com.company.demo.aotuwire.Dept"></bean>
注:根据属性名称进行自动装配,切记引入的外部bean的id一定要和本类的属性名称一样,spring才能进行自动装配
(2)byType:通过识别属性类型进行自动装配
<!--通过属性类型进行自动装配有个问题,就是被引入类型的Bean对象只能有一个,不然会报错-->
<bean id="emp" class="com.company.demo.aotuwire.Emp" autowire="byType"></bean>
<!--外部Bean对象只能有一个-->
<bean id="dept" class="com.company.demo.aotuwire.Dept"></bean>
<!--<bean id="dept2" class="com.company.demo.aotuwire.Dept"></bean>-->
1万+



被折叠的 条评论
为什么被折叠?



