spring
引入Spring
在没有使用spring的时候写代码的三层架构的时候,dao层与service紧密联系,service与controller紧密联系,在service中new的dao接口的实现类,在controller中new的是service的实现类,这种联系很紧密,高耦合
图解spring是如何降低耦合度的
原始模式
在最初的代码是要使用的话,就new这个接口的实现对象,假如我们换实现类后,还需要更改源代码,这样耦合度高,加入我们项目上线后,我们要更改某个实现,需要更改源代码,需要从新编译部署运行,十分麻烦
工厂模式降低解耦
使用工厂模式,让new实现类的工作交给工厂来创建,这样虽然具体的业务和实现类是断开了耦合,但是工厂与实现类还是高耦合,我们想修改实现类,还得修改工厂中的方法,导致还是需要从新编译打包部署运行
spring的IOC
使用spring来管理我们的实体对象,只需要将配置文件中的实现更改,无需更改源代码,当我们需要跟换实现的时候,只需要将配置文件中的class更改就行了,无需重新编译,十分方便,从而使得代码与代码之间的耦合度降低,让类与配置文件有紧密联系
耦合与内聚
IOC
IoC
⚫ IoC(Inversion Of Control)控制反转,Spring反向控制应用程序所需要使用的外部资源
⚫ Spring控制的资源全部放置在Spring容器中,该容器称为IoC容器
通俗来将就是原本我们使用一个类需要将这个类new出来,是我们主动去创建这个类
而把这个类交给spring的ioc管理后,spring会把这个类放在他的ioc容器中,然后我们要使用就去容器中获取就是,被动获取
spring的applicationContext.xml关于IOC的配置
记录spring的applicationContext.xml配置文件中的bean标签的使用
bean
⚫ 名称:bean
⚫ 类型:标签
⚫ 归属:beans标签
⚫ 作用:定义spring中的资源,受此标签定义的资源将受到spring控制
⚫ 格式:
< beans>
< bean />
< /beans>
基本属性id属性和class属性< bean id=“dog” class=“com.fs.iocdemo.Dog”/>
< bean id=“dog” class=“com.fs.iocdemo.Dog”/>
◆ id:bean的名称,通过id值获取bean
◆ class:bean的类型
类的准备
创建一个Dog类,提供一个方法来输出语句便于观察
package com.fs.iocdemo;
public class Dog {
public void testBean(){
System.out.println("Dog对象被spring管理了");
}
}
配置文件applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 把Dog对象交给spring的ioc容器管理,默认通过无参构造方法创建-->
<bean id="dog" class="com.fs.iocdemo.Dog"/>
</beans>
测试方法
//测试bean是否被ioc管理
@Test
public void testBean() {
//创建spring的ioc容器对象,传递的参数为配置文件的名,类路径下的配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过配置文件中的id从spring的ioc容器中获取Dog对象
Dog dog = (Dog) applicationContext.getBean("dog");
//调用方法
dog.testBean();
}
输出结果与解释
说明我们的Dog已经从spring的IOC容器中获取到了
基本属性name < bean id=“cat” name=“cat1,cat2” class=“com.fs.iocdemo.Cat”/>
◆ name:bean的名称,可以通过name值获取bean,用于多人配合时给bean起别名
类的准备
创建一个Cat类,来演示一个配置文件中可以将多个类交给spring的Ioc管理,和演示name属性
package com.fs.iocdemo;
public class Cat {
public void testName(){
System.out.println("cat被spring的ioc管理了");
}
}
配置文件applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 把Dog对象交给spring的ioc容器管理,默认通过无参构造方法创建-->
<bean id="dog" class="com.fs.iocdemo.Dog"/>
<!--把Cat对象交给spring的ioc容器管理,并且给多个name(起别名),通过getBean可以给别名从ioc中的到对象-->
<bean id="cat" name="cat1,cat2" class="com.fs.iocdemo.Cat"/>
</beans>
测试方法
//测试给bean起别名后,通过别名从ioc中获取对象
@Test
public void testName() {
//创建spring的ioc容器对象,传递的参数为配置文件的名,类路径下的配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过配置文件中的id从spring的ioc容器中获取Dog对象
// Cat cat = (Cat) applicationContext.getBean("cat");
//使用别名也可以从spring的ioc获取出Cat对象
// Cat cat = (Cat) applicationContext.getBean("cat1");
Cat cat = (Cat) applicationContext.getBean("cat2");
//调用方法
cat.testName();
}
输出结果与解释
由上面代码可得,getBean(这里可以传递id,也可以传递name),别名起多个,也可以从springIOC中获取
基本属性scope < bean id=“cat3” scope=“singleton” class=“com.fs.iocdemo.Cat”/>
bean属性scope
⚫ 名称:scope
⚫ 类型:属性
⚫ 归属:bean标签
⚫ 作用:定义bean的作用范围
⚫ 格式:< bean scope=“singleton”>
⚫ 取值:
◆ singleton:设定创建出的对象保存在spring容器中,是一个单例的对象
◆ prototype:设定创建出的对象保存在spring容器中,是一个非单例的对象
◆ request、session、application、 websocket :设定创建出的对象放置在web容器对应的位置
类依然使用Cat类
配置文件applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 把Dog对象交给spring的ioc容器管理,默认通过无参构造方法创建-->
<bean id="dog" class="com.fs.iocdemo.Dog"/>
<!--把Cat对象交给spring的ioc容器管理,并且给多个name(起别名),通过getBean可以给别名从ioc中的到对象-->
<bean id="cat" name="cat1,cat2" class="com.fs.iocdemo.Cat"/>
<!--bean中的scope属性默认是单例的(singleton)而且是俄汉式,就是类一加载就创建(不写scope就是单例)
scope属性的prototype是多列的,但是是懒汉式,需要的后才创建
-->
<!-- <bean id="cat3" scope="singleton" class="com.fs.iocdemo.Cat"/>-->
<bean id="cat3" scope="prototype" class="com.fs.iocdemo.Cat"/>
</beans>
测试方法
//测试bean标签的scope属性单例和多列模式
@Test
public void testScope() {
//创建spring的ioc容器对象,传递的参数为配置文件的名,类路径下的配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
/*
<bean id="cat2" scope="singleton" class="com.fs.iocdemo.Cat"/>
//单列模式获取多个对象,看地址是否一样,一样说明确实是单例
Cat cat = (Cat) applicationContext.getBean("cat3");
Cat cat1 = (Cat) applicationContext.getBean("cat3");
Cat cat2 = (Cat) applicationContext.getBean("cat3");
//输出看下地址值
System.out.println(cat);//com.fs.iocdemo.Cat@7a765367
System.out.println(cat1);//com.fs.iocdemo.Cat@7a765367
System.out.println(cat2);//com.fs.iocdemo.Cat@7a765367
*/
//多列模式下输出的地址值不一样,所明确实是的
//多列模式spring是不会吧对象放在ioc中的,只是帮我们new的一下
//<bean id="cat3" scope="prototype" class="com.fs.iocdemo.Cat"/>
Cat cat = (Cat) applicationContext.getBean("cat3");
Cat cat1 = (Cat) applicationContext.getBean("cat3");
Cat cat2 = (Cat) applicationContext.getBean("cat3");
//输出看下地址值
System.out.println(cat);//com.fs.iocdemo.Cat@7a765367
System.out.println(cat1);//com.fs.iocdemo.Cat@76b0bfab
System.out.println(cat2);//com.fs.iocdemo.Cat@17d677df
}
运行结果
在测试代码的输出语句中有显示,可以得到当单例的时候,得到的对象都是同一个,而且是从IOC中获取的对象,而多列的时候,获取的对象是多个,而且不是从SpringIOC中获取的,因为是多列,每获取spring只帮new出来,而不会存储在IOC中
Bean的生命周期 < bean id=“cat4” scope=“prototype” init-method=“init” destroy-method=“destroy” class=“com.fs.iocdemo.Cat”/>
bean生命周期
⚫ 名称:init-method,destroy-method
⚫ 类型:属性
⚫ 归属:bean标签
⚫ 作用:定义bean对象在初始化或销毁时完成的工作
⚫ 格式:<bean init-method=“init” destroy-method="destroy>
⚫ 取值:bean对应的类中对应的具体方法名
⚫ 注意事项:
◆ 当scope=“singleton”时,spring容器中有且仅有一个对象,init方法在创建容器时仅执行一次
◆ 当scope=“prototype”时,spring容器要创建同一类型的多个对象,init方法在每个对象创建
时均执行一次
◆ 当scope=“singleton”时,关闭容器会导致bean实例的销毁,调用destroy方法一次
◆ 当scope=“prototype”时,对象的销毁由垃圾回收机制gc()控制,destroy方法将不会被执行
类的准备
在类中创建一个构造方法,两个随意的方法,名字也随意,打印输出一下,方便查看效果
package com.fs.iocdemo;
public class Cat {
public Cat() {
System.out.println("构造方法执行了");
}
public void testName(){
System.out.println("cat被spring的ioc管理了");
}
public void init(){
System.out.println("init方法执行了");
}
public void destroy(){
System.out.println("destroy方法执行了");
}
}
配置文件applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 把Dog对象交给spring的ioc容器管理,默认通过无参构造方法创建-->
<bean id="dog" class="com.fs.iocdemo.Dog"/>
<!--把Cat对象交给spring的ioc容器管理,并且给多个name(起别名),通过getBean可以给别名从ioc中的到对象-->
<bean id="cat" name="cat1,cat2" class="com.fs.iocdemo.Cat"/>
<!--bean中的scope属性默认是单例的(singleton)而且是俄汉式,就是类一加载就创建(不写scope就是单例)
scope属性的prototype是多列的,但是是懒汉式,需要的后才创建
-->
<!-- <bean id="cat3" scope="singleton" class="com.fs.iocdemo.Cat"/>-->
<bean id="cat3" scope="prototype" class="com.fs.iocdemo.Cat"/>
<!--
init-method:给的类中的一个方法 在对象创建后执行
destroy-method:给类中的一个方法 在ioc容器正常关闭的时候运行,需要使用ClassPathXmlApplicationContext中的close()关闭才会执行
-->
<bean id="cat4" scope="prototype" init-method="init" destroy-method="destroy" class="com.fs.iocdemo.Cat"/>
</beans>
测试方法
//测试bean的生命周期
@Test
public void testInitDestroy() {
//创建spring的ioc容器对象,传递的参数为配置文件的名,类路径下的配置文件
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//不需要从ioc中获得对象,因为spring一读取配置文件就创建对象存在ioc中,所以默认无参构造方法就执行了
// <bean id="cat4" scope="singleton" init-method="init" destroy-method="destroy" class="com.fs.iocdemo.Cat"/>
/*
单例模式(单列模式创建的对象会交给springIOC管理)
构造方法执行了
构造方法执行了
init方法执行了
destroy方法执行了
*/
// <bean id="cat4" scope="prototype" init-method="init" destroy-method="destroy" class="com.fs.iocdemo.Cat"/>
//多列测试
Cat cat = (Cat) applicationContext.getBean("cat4");
Cat cat2 = (Cat) applicationContext.getBean("cat4");
Cat cat3 = (Cat) applicationContext.getBean("cat4");
/*
多列模式下不会执行destroy方法
(多列创建的对象不会交个spring的IOC管理,创建后就没有被真正的关闭,而是被jvm垃圾回收,所以不会立马执行destroy)
构造方法执行了
构造方法执行了
init方法执行了
构造方法执行了
init方法执行了
构造方法执行了
init方法执行了
*/
//ClassPathXmlApplicationContext 的close()关闭spring让destroy执行
applicationContext.close();
}
运行结果
代码中有注释运行结果,也有解释.
bean对象的创建方式
使用静态工厂和实例工厂创建bean
使用静态工厂方式
bean对象创建方式(了解)
⚫ 名称:factory-bean
⚫ 类型:属性
⚫ 归属:bean标签
⚫ 作用:定义bean对象创建方式,使用静态工厂的形式创建bean,兼容早期遗留系统的升级工作
⚫ 格式:
⚫ 取值:工厂bean中用于获取对象的静态方法名
⚫ 注意事项:
◆ class属性必须配置成静态工厂的类名
静态工厂类
静态工厂获取Dog只需要FactoryStatic.Dog就能得到Dog对象
package com.fs.factory;
import com.fs.iocdemo.Dog;
public class FactoryStatic {
//这个静态工厂,用于生产dog
public static Dog getDog(){
return new Dog();
}
}
实例工厂类
实例工厂获取Dog,首先需要 new FactoryBean().getDog() 才能获得Dog对象
package com.fs.factory;
import com.fs.iocdemo.Dog;
public class FactoryBean {
//这是个实体类工厂,用于生产Dog
public Dog getDog(){
return new Dog();
}
}
配置文件applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 把Dog对象交给spring的ioc容器管理,默认通过无参构造方法创建-->
<bean id="dog" class="com.fs.iocdemo.Dog"/>
<!--把Cat对象交给spring的ioc容器管理,并且给多个name(起别名),通过getBean可以给别名从ioc中的到对象-->
<bean id="cat" name="cat1,cat2" class="com.fs.iocdemo.Cat"/>
<!--bean中的scope属性默认是单例的(singleton)而且是俄汉式,就是类一加载就创建(不写scope就是单例)
scope属性的prototype是多列的,但是是懒汉式,需要的后才创建
-->
<!-- <bean id="cat3" scope="singleton" class="com.fs.iocdemo.Cat"/>-->
<bean id="cat3" scope="prototype" class="com.fs.iocdemo.Cat"/>
<!--
init-method:给的类中的一个方法 在对象创建后执行
destroy-method:给类中的一个方法 在ioc容器正常关闭的时候运行,需要使用ClassPathXmlApplicationContext中的close()关闭才会执行
-->
<bean id="cat4" scope="prototype" init-method="init" destroy-method="destroy" class="com.fs.iocdemo.Cat"/>
<!-- 配置静态工厂交给spring管理
因为获取Dog的方法是静态的,当我们从ioc获取出静态工厂就直接调用getDog方法就能拿到Dog
//实际是将getDog的返回值存储在ioc容器中
-->
<bean id="factoryStatic" class="com.fs.factory.FactoryStatic" factory-method="getDog"/>
<!-- 配置实体工厂-->
<bean id="factoryBean" class="com.fs.factory.FactoryBean"/>
<!-- 然后在实体工厂中获取Dog
factory-bean="factoryBean" : 关联上面的实体工厂
factory-method="getDog" : 调用实体工厂的方法
//实际是将Dog存到ioc容器中
-->
<bean id="factoryBeanDog" factory-bean="factoryBean" factory-method="getDog"/>
</beans>
测试方法
//测试工厂获取对象
@Test
public void testFactory() {
//创建spring的ioc容器对象,传递的参数为配置文件的名,类路径下的配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//<bean id="factoryStatic" class="com.fs.factory.FactoryStatic"/>
Dog factoryStaticDog = (Dog) applicationContext.getBean("factoryStatic");
factoryStaticDog.testBean();
/*
<bean id="factoryBean" class="com.fs.factory.FactoryBean"/>
<!-- 然后在实体工厂中获取Dog
factory-bean="factoryBean" : 关联上面的实体工厂
factory-method="getDog" : 调用实体工厂的方法
//实际是将Dog存到ioc容器中
-->
<bean id="factoryBeanDog" factory-bean="factoryBean" factory-method="getDog"/>
*/
Dog factoryBeanDog = (Dog) applicationContext.getBean("factoryBeanDog");
factoryBeanDog.testBean();
}