文章目录
一、spring
1.1 SpringIO的概念
名词解释:
IOC(Inversion of control):控制反转,是一种设计思想。DI(dependence injection):依赖注入是实现IOC的一种方法。
我们之前的编码中,对象的创建与对象间的依赖关系完全硬编码出现在程序总,对象也是由我们自己来创建和控制的。
而控制反转的意思就是将创建对象的权利交给“第三方”,也就是我们可以交给spring框架,spring框架就获得了创建对象的去哪里。对象创建创建的权利发生了改变。
上述的两个名词其实就是一个意思,只是出于不同的角度提出的。
1.2 Spring IOC理论推导
我们在引入IOC思想之前,进行开发使用的模式是MVC,以用户注册为例,一般分为:
- UserDao 数据访问层接口
- UserDaoImpl 数据访问层实现类
- UserService 业务层接口
- UserService 业务层接口的实现类
- UserServlet Web层
数据访问层的代码
//数据库访问层代码
public class UserDao{
public User queryByLoginName(String name){
}
public void save(User user){
}
}
业务逻辑层代码
//业务逻辑层代码
public class UserService{
//调用dao,创建dao的对象
private UserDao userDao=new UserDao();
public void userRegister(User user){
}
}
业务层的代码维护了数据访问层的代码,这样会存在一些问题,就是当我们的需求发生改变时,就需要改变大量的原有代码。
当引入IOC思想之后,我们不在自己new对象了。
业务逻辑层代码:
public class UserService{
//调用dao,创建dao的对象
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao=userDao;
}
public void userRegister(User user){
//userDao.任何方法或者属性均会空指针
}
}
上面的程序中就不需要new对象了。引入set方法,就可以将创建对象的权利转移,之前的是可以主动创建对象,现在呢,程序就变成了被动的传入一个对象。从一定程度上降低了代码的耦合度。有利于业务的实现。
1.3 spring框架的入门
(1)创建一个MAVEN项目,在创建完成之后,点开pom.xml文件,添加spring的依赖。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
(2)在MAVEN项目中创建如下的目录结构,main文件夹下面的resources创建spring的配置文件(这里我命名为:applicationContext.xml)
(3)让spring管理资源,在配置文件中配置service和dao
<bean id="userService" class="com.gx.Service.UserService">
</bean>
<bean id="userDao1" class="com.gx.dao.daoimpl.UserDao1">
</bean>
(4)测试Spring的配置是否成功
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
UserDao1 userDao1 = context.getBean("userDao1", UserDao1.class);
System.out.println(userDao1);
System.out.println(userService);
}
1.3 spring配置解释
1.3.1 ApplicationContext的三个常用类对象
- ClassPathXmlApplicationContext:加载类路径下的配置文件,要求配置文件必须在类路径下
- FileSystemXmlApplicationContext:加载磁盘任意路径下的配置文件(前提要有访问权限)
- AnnotationConfigApplicationContext:用于读取注解创建Spring容器
1.3.2 ApplicationContext和BeanFactory的区别
BeanFactory 才是 Spring 容器中的顶层接口。
ApplicationContext 是它的子接口。
BeanFactory 和 ApplicationContext 的区别:
创建对象的时间点不一样。
ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
BeanFactory:什么使用什么时候创建对象。
1.4 IOC 中 bean 标签
1.4.1 bean 标签
作用:将创建对象的权力交给Spring容器,默认情况下调用的是无参构造函数,没有无参构造不能创建。
其中的属性:
- id:对象在spring容器中的唯一标识。用于获取对象
- class:指定类的全路径类名。使用反射创建对象
- scope:指定对象的作用范围
- init-method:类的初始化方法
- destory-method:类的销毁方法
1.4.2 创建bean的三种方式
一、使用默认的构造方法
<!--在默认情况下:它会根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。-->
<bean id="userService" class="com.gx.Service.UserService"> </bean>
二、spring管理静态工厂,使用静态工厂的方法创建对象,并存入spring容器
Runtime runtime=RunTime.getRuntime();
获取Runtime的实例必须通过Runtime的静态getRuntime()方法才能够获取。通过spring的配置获取如下
<bean id="runtime" class="java.lang.Runtime" factory-method="getRuntime"/>
三、spring管理实例工厂(使用某个类中的方法创建对象存入spring容器)
Java代码中,获取FactoryUserService对象的是在ServiceFactoryDemo中的getFactoryUserService方法中获取。
public class ServiceFactoryDemo {
//创建UserService对象
public FactoryUserService getFactoryUserService(){
//System.out.println("创建工厂方法");
return new FactoryUserService();
}
}
在spring配置中如下:
<bean id="serviceFactoryDemo " class="com.gx.Service.ServiceFactoryDemo" />
<bean id="factoryUserService" factory-method="getFactoryUserService" factory-bean="serviceFactoryDemo ">
1.4.3 bean的作用范围和生命周期
范围属性:scope
作用:用于指定bean的作用范围,spring容器会根据我们设置的scope属性来选择创建对象的时机。
取值:
- singleton :默认值,单例的
- prototype :多例的.
- request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中
- session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中
- WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session.
生命周期:
(1)单例对象(scope=“singleton”)一个应用只有一个对象
对象出生:当应用加载,创建容器时,对象就被创建了。
对象活着:只要容器在,对象一直活着。
对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
(2)多例对象(scope=“prototype”)每次访问对象时,都会重新创建对象的实例
对象出生:当使用对象时,创建新的对象实例。
对象活着:只要对象在使用中,就一直活着。
对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了。
单例模式:
在代码获取容器的时候,当使用ApplicationContext来接受容器时,不能使用手动关闭close方法,这个方法在destory-method时执行
使用ClassPathXmlApplicationContext来接受时,我们可以调用close方法。
多例模式:
对象的销毁不由我们控制,当对象长时间不使用并且不被其他对象所调用的时候,会被Java垃圾回收器回收
二、Spring的依赖注入
依赖注入:Dependency Injection。它是 spring 框架核心 ioc 的具体实现。我们的程序在编写时,通过控制反转,把对象的创建
交给了 spring,但是代码中不可能出现没有依赖的情况。
IOC只是降低他们的依赖关系,但不会消除。
注入的类型
- 基本数据类型和String
- 其他的bean类型(配置文件或注解中配置过的bean)
- 复杂类型/集合
2.1 构造函数注入
通过配置文件的方式,让spring框架为我们注入。使用的标签constructor-arg
标签中的属性:
- type:指定参数在构造函数中的数据类型
- name:指定参数在构造函数中的名称
- index:指定参数在构造函数参数列表的索引位置
- value:它能赋的值是基本数据类型和 String 类型
- ref:它能赋的值是其他 bean 类型(配置文件中配置过的 bean)
Java代码:UserService 中进行UserDao 的注入
public class UserService {
private UserDao userDao1;
//使用构造方法对对象进行注入
public UserService(UserDao userDao){
this.userDao1=userDao;
}
}
<!--使用构造方法对对象进行注入-->
<bean id="userService" class="com.gx.Service.UserService">
<!--构造方法注入的ref就是引用javabean对象在spring容器中的id值-->
<constructor-arg ref="userDao2"></constructor-arg>
</bean>
<bean id="userDao1" class="com.gx.dao.daoimpl.UserDao1">
</bean>
<bean id="userDao2" class="com.gx.dao.daoimpl.UserDao2">
</bean>
2.2 set方法注入
使用的标签:property
属性:
- name:找的是类中 set 方法后面的部分
- value:给属性赋值是基本数据类型和 string 类型的
- ref:给属性赋值是其他 bean 类型的
Java代码:ConstructorDemo 中存在3个属性。
public class ConstructorDemo {
private String name;
private Integer age;
private Date birthday;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public void show(){
System.out.println("show方法调用"+name+","+age+","+birthday);
}
}
配置文件中进行配置:
<bean id="constructorDemo" class="com.gx.Service.ConstructorDemo">
<property name="name" value="詹姆斯"/>
<property name="age" value="32"/>
<property name="birthday" ref="now"/>
</bean>
<!--将date对象的创建交给spring容器 ,配置日期对象-->
<bean id="now" class="java.util.Date"></bean>
2.3 使用p标签进行注入
Java代码与上面的set注入的相同,只是在配置中会有不一样的地方
<bean id="accountService"
class="com.itheima.service.impl.AccountServiceImpl4"
p:name="test" p:age="21" p:birthday-ref="now"/>
</beans>
<!--将date对象的创建交给spring容器 ,配置日期对象-->
<bean id="now" class="java.util.Date"></bean>
2.4 注入复杂类型(集合)
创建一个Java类,其中属性分别为数组以及常见的集合类型。在这里插入代码片
public class fuzaInjection {
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties myProps;
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
public void show(){
System.out.println(Arrays.toString(myStrs));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap);
System.out.println(myProps);
}
}
进行配置:
<!--复杂类型的注入-->
<bean id="fuzaInjection" class="com.gx.Service.fuzaInjection">
<property name="myStrs">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<property name="mySet">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<property name="myList">
<list>
<value>aaa</value>
<value>BBB</value>
<value>cccc</value>
</list>
</property>
<property name="myMap">
<map>
<entry key="map1" value="Amap"></entry>
<entry key="map2">
<value>Bmap</value>
</entry>
</map>
</property>
<property name="myProps">
<props>
<prop key="prop1">prop1</prop>
<prop key="prop2">prop2</prop>
<prop key="prop4">prop3</prop>
</props>
</property>
</bean>
<bean id="fuzaInjectionConstructor" class="com.gx.Service.fuzaInjectionConstructor">
<constructor-arg name="mySet">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</constructor-arg>
<constructor-arg name="myMap">
<map>
<entry key="map1">
<value>111</value>
</entry>
<entry key="map2" value="222"></entry>
</map>
</constructor-arg>
<constructor-arg name="myProps">
<props>
<prop key="prop1">pro1</prop>
<prop key="prop2">pro2</prop>
<prop key="prop3">pro3</prop>
</props>
</constructor-arg>
</bean>
复杂类型注入的总结:
用于给List结构集合注入的标签:list、array、set
用于给map结构集合注入的标签:map、props
2.5 构造和set注入的区别
构造函数注入:
优点:注入数据时,必须注入数据,否则无法创建对象。
缺点:改变了bean对象的实例化方法,造成对象创建时,不使用构造函数中的某一个数据的时候,也必须创建该数据。
set方法注入:
优点:创建对象的时候没有限制,可以直接使用默认的构造方法创建bean对象。
缺点:如果某个成员变量必须有值的话,则获取对象时有可能set方法不执行。