这里写目录标题
一级目录
二级目录
三级目录
一Spring简介
1、Spring简介
Spring是于2003 年兴起的一个轻量级(框架api与代码耦合很低)的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。
Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。
Spring官方主页(http://spring.io
)有两句话:
Let’s build a better Enterprise.
我们共同来构建更好的企业应用。
Spring helps development teams everywhere build simple, portable, fast and flexible JVM-based systems and applications.
Spring帮助全世界的开发团队构建简单、便携、快速和灵活的基于JVM的系统和应用。
2、Spring优点
1. 面向对象的设计比任何实现技术(比如JAVA EE)都重要
2. 低侵入式设计,代码污染极低
3. 独立于各种应用服务器,基于Spring框架的应用,可以真正实现Write Once,Run Anywhere的承诺
4. Spring的IoC/DI机制降低了业务对象替换的复杂性,提高了组件之间的解耦
5. Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式管理,从而提供了更好的复用
6. Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问
7. Spring并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或全部
8. 面向接口编程,而不是针对类编程。Spring将使用接口的复杂度降低到零
3、为什么要面向接口编程
面向接口编程就是先把客户的业务逻辑先提取出来,作为接口,业务具体实现通过该接口的实现类来完成。 当客户需求变化时,只需编写该业务逻辑的新的实现类,通过更改配置文件(例如Spring框架)中该接口的实现类就可以完成需求,不需要改写现有代码,减少对系统的影响。
4 spring模块
二 Spring IoC/DI控制翻转
我们先理解一下 传统面向对象思想在两个bean类之间的依赖及用法写法:
/**
* Created by @author LiuChunhang on 2020/3/14.
*/
public class Girl {
public String love;
public void answer(){
System.out.println("boy:"+love+",\n"+"girl:"+"I Love you.");
}
public String getLove() {
return love;
}
public void setLove(String love) {
this.love = love;
}
}
/**
* Created by @author LiuChunhang on 2020/3/14.
*/
public class Boy {
public Girl mylove ;
public Girl getMylove() {
return mylove;
}
public void setMylove(Girl mylove) {
this.mylove = mylove;
}
public static void main(String[] args) {
Girl girl = new Girl();
girl.setLove(" I Want you");
Boy boy = new Boy();
boy.setMylove(girl);
boy.getMylove().answer();
}
调用另一个对象的时候 必须初始化/实例化对象 把对象new出来 才能依赖!
我们下面来看看ioc解决了什么:
1、什么是IOC?
Inversion of Control,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection),即依赖注入,IoC等价于DI。 如何理解“控制反转”好呢?理解好它的关键在于我们需要回答如下四个问题:
- 谁控制谁?
- 控制什么?
- 为何是反转?
- 反转了什么?
2定义
IOC:就是由 Spring IOC 容器来负责对象的生命周期和对象之间的关系。
IOC其思想是反转资源获取的方向。类的对象创建及对象之间的关系从代码中移植到配置文件中,由Spring配置文件(即:IOC容器)负责对象的创建及对象之间关系的管理。
3环境搭建
spring的maven依赖
<dependencies>
<!-- spring4.3.2 -->
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
</dependencies>
spring的配置文件 :负责类的创建和管理类之间的依赖关系
在src/main/resources/下创建配置文件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" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.2.xsd">
<!--bean管理-->
<bean id="BeautifulGirl" class="com.offcn.spring.BeautifulGirl"></bean>
<bean id="YongBoy" class="com.offcn.spring.YongBoy">
<property name="girl" ref="BeautifulGirl"/>
</bean>
</beans>
spring管理下的类的写法
public class Girl {
public String love;
public void answer(){
System.out.println("boy:"+love+",\n"+"girl:"+"I Love you.");
}
public String getLove() {
return love;
}
public void setLove(String love) {
this.love = love;
}
}
public class Boy {
public Girl mylove ;
public void sout(){
mylove.answer();
}
public Girl getMylove() {
return mylove;
}
public void setMylove(Girl mylove) {
this.mylove = mylove;
}
public class BoyandGirl {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Boy boy = (Boy) applicationContext.getBean("Boy");
boy.sout();
}
}
注:
4 对于 (1) 的问题解答及注意事项
问题解答
1. 谁控制谁:在传统的开发模式下,我们都是采用直接 new 一个对象的方式来创建对象,也就是说你依赖的对象直接由你自己控制,但是有了 IoC 容器后,则直接由 IoC 容器来控制。所以“谁控制谁”,当然是 IoC 容器控制对象。
2. 控制什么:控制对象。
3. 什么是反转:没有 IoC 的时候我们都是在自己对象中主动去创建被依赖的对象,这是正转。但是有了 IoC 后,所依赖的对象直接由 IoC 容器创建后注入到被注入的对象中,依赖的对象由原来的主动获取变成被动接受,所以是反转。
4. 哪些方面反转了:所依赖对象的获取方式被反转了。
注意事项
1、spring配置文件(IOC容器)中把class叫做bean。
<bean id="loginDao" class="com.offcn.spring.dao.LoginDao"/>
id:表示的是容器中bean的唯一标识,通常用于查找bean或者被引用。
<bean property=”” ref=”id”>
class:需要被IoC容器管理的bean的完全限定名,要求:包名+类名,不要扩展名
2、单独加载一个ioc容器:
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
3、加载多个ioc容器:
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext1.xml","applicationContext2.xml"});
3、通过getBean()方法获取容器中的bean的常用形式
方式一:context.getBean("id");
方式二:LoginService service=context.getBean(类名.class);
5 三种注入方式 ,掌握任意一种 均可 (setter最简单最常用)
1构造器注入:(在类中生成对于元素的构造方法)构造器注入,顾名思义就是被注入的对象通过在其构造方法中声明依赖对象的参数列表,让外部知道它需要哪些依赖对象。
①按照参数索引注入
<bean
id="crmDaoImpl"
class="com.offcn.crm.dao.impl.CrmDaoImpl">
<!-- 基于构造方法索引注入 -->
<constructor-arg index="0" value="140"></constructor-arg>
<constructor-arg index="1" value="吕洞宾"></constructor-arg>
<constructor-arg index="2" ref="date"></constructor-arg>
</bean><!-- 依赖Date类对象 -->
<!-- 通过ioc容器实例化Date类对象 -->
<bean id="date" class="java.util.Date"></bean>
②按照参数类型注入
<bean
id="crmDaoImpl"
class="com.offcn.crm.dao.impl.CrmDaoImpl">
<!-- 基于构造方法类型注入 -->
<constructor-arg type="int" value="160"></constructor-arg>
<constructor-arg type="java.lang.String"
value="铁拐李"></constructor-arg>
<constructor-arg
type="java.util.Date" ref="date"></constructor-arg>
</bean>
<!-- 通过ioc容器实例化Date类对象 -->
<bean id="date" class="java.util.Date"></bean>
③按照参数名称注入
<!--构造方法注入 名称 -->
<bean id="beautifulGirl" class="com.offcn.spring.BeautifulGirl">
<constructor-arg name="like" value="抽烟、喝酒、烫头"></constructor-arg>
<constructor-arg name="date" ref="date"></constructor-arg>
<constructor-arg name="age" value="26"></constructor-arg>
</bean>
<!-- 通过ioc容器实例化Date类对象 -->
<bean id="date" class="java.util.Date"></bean>
*2setter 方法注入(最常用的方法):(在类中生成元素的setter方法) 对于 JavaBean 对象而言,我们一般都是通过 getter 和 setter 方法来访问和设置对象的属性。
所以,当前对象只需要为其所依赖的对象提供相对应的 setter 方法,就可以通过该方法将相应的依赖对象设置到被注入对象中。*
①字面值注入
<bean
id="crmDaoImpl"
class="com.offcn.crm.dao.impl.CrmDaoImpl">
<property name="age" value="100"></property>
<property name="name" value="乔峰"></property>
<property name="birthday" ref="date"></property>
</bean>
<!-- 通过ioc容器实例化Date类对象 -->
<bean id="date" class="java.util.Date"></bean>
②引用类型注入
<!-- 定义java.util.Date bean -->
<bean id="date" class="java.util.Date"></bean>
<bean id="user" class="com.offcn.spring.user.User">
<property name="name" value="scott"></property>
<property name="age" value="12"></property>
<property name="sex" value="m"></property>
<property name="flag" value="true"></property>
<!-- 注入日期对象 -->
<property name="birthday" ref="date"></property>
</bean>
③注入时的注意事项
1、字面值注入用value属性,引用类型注入用ref属性
<property name="name" value="乔峰"></property>
<property name="birthday" ref="date"></property>
2、setter方法注入时要求每个属性必须有set方法,如果属性没有set方法报以下异常:
org.springframework.beans.NotWritablePropertyException
3接口方式注入 :接口方式注入显得比较霸道,因为它需要被依赖的对象实现不必要的接口,带有侵入性。一般都不推荐这种方式。这里不再举例说明
....................................
.............................
..............................
6 集合类型的属性元素值注入(也不太常用,这里简单说明一下)
类中List集合类型属性cars;
private List<Car> cars;
<!-- 装配集合属性 -->
<bean id="user" class="com.offcn.spring.helloworld.User">
<property name="userName" value="Jack"></property>
<property name="cars">
<!-- 使用 list 元素来装配集合属性 -->
<list>
<ref bean="car1"/>
<ref bean="car2"/>
</list>
</property>
</bean>
7 P标签注入与自动装配
1p标签注入:
首先引入 P 标签的命名空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" <!-- P标签的命名空间 -->
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"
P标签应用:
1、第一步引入p标签命名空间(配置文件中直接输入<p:>会直接自动生成引入该命名空间)
2、引入属性直接写 p:[属性名]=[属性值]
3、引入引用对象写:p[属性名-ref]=[属性值]
p:age="200" p:birthday-ref="date"
p:age="200"
等价于<property name="age" value="200"></property>
P:birthday-ref=”data”
等价于<property name="birthday" ref=”date”></property>
2自动装配(注入配置文件中已经实例化过的类,注入的一个类的类型在配置文件中不能多于一个,否则会报错)
<bean id=”” class=”” autowire=””/>
autowire=byName/byType/constructor
1. byType:从IoC容器中找到与bean中的属性类型相同的bean对象注入。
注意事项:IOC容器中,同一类型不可定义两次。
2.byName:从IoC容器中找到与bean中的属性名称相同的bean对象注入。
3.constructor:把与Bean的构造器入参具有相同类型的其他Bean自动装配到Bean构造器的对应入参中。值的注意的是,具有相同类型的其他Bean这句话说明它在查找入参的时候,还是通过Bean的类型来确定。
构造器中入参的类型为Role
4.(现在已不再使用)autodetect它首先会尝试使用constructor进行自动装配,如果失败再尝试使用byType。不过,它在Spring3.0之后已经被标记为@Deprecated。
5.默认自动装配
默认情况下,default-autowire属性被设置为none,标示所有的Bean都不使用自动装配,除非Bean上配置了autowire属性。
如果你需要为所有的Bean配置相同的autowire属性,有个办法可以简化这一操作。
在根元素Beans上增加属性default-autowire="byType"。
<beans default-autowire="byType">
自动装配 autowire总结
Spring自动装配的优点不言而喻。
但是事实上,在Spring XML配置文件里的自动装配并不推荐使用,
因为最大的缺点在于不确定性。
或者除非你对整个Spring应用中的所有Bean的情况了如指掌,
不然随着Bean的增多和关系复杂度的上升,情况可能会很糟糕。
8 IOC管理创建对象的三种方式(了解)
.8.1第一种默认方式是使用无参构造方法创建对象(默认方式)
这里不再举例说明........................................
8.2第二种使用静态工厂方式创建对象
public class Order {
// 对象创建
private static Order order = new Order();
// 私有化构造方法
private Order() {
}
// 获取该类对象的静态方法
public static Order getOrderInstace() {
return order;
}
}
<!-- 通过静态方法创建对象 -->
<bean
id="order"
class="com.offcn.spring.order.Order"
factory-method="getOrderInstace"></bean> <!-- 静态工厂方式-->
8.3使用实例工厂方式创建对象
public class Item {
private static Item item = new Item();
private Item() {
}
public Item getItemInstance() {
return item;
}
}
<!-- 声明Item bean -->
<bean id="itemService" class="com.offcn.spring.order.Item"></bean>
<!-- 通过实例工厂方法创建对象 -->
<bean
id="item"
factory-bean="itemService"
factory-method="getItemInstance"> <!-- 静态工厂方式-->
</bean>
8.4注入格式时间案例
通过ioc容器注入yyyy-MM-dd格式的时间:
/**通过ioc容器把'2018-12-13'格式的字符串注入给startDate*/
private Date startDate;
<!-- SimpleDateFormat -->
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
<!--
<bean id="dataInstance"
factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2018-12-13" />
</bean>
-->
<!--
<bean id="carDate" class="com.offcn.crm.dao.entity.CarDate">
<property name="startDate" ref="dataInstance"></property>
</bean>
-->
<bean id="carDate" class="com.offcn.crm.dao.entity.CarDate">
<property name="startDate">
<bean factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2019-12-13" />
</bean>
</property>
</bean>
9 ioc管理bean的生命周期与作用域
bean的生命周期
Bean在IOC容器中是有生命周期的,bean中会给出一个初始化方法和一个销毁方法,这两个方法都是ioc容器负责调用。
定义bean的初始化方法:init-method=""
定义bean的销毁方法:destroy-method="",注意此方法需要关闭IoC容器的关闭。
初始化执行:
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
......
销毁方法执行:
context.close();
bean的作用域
默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实例, 整个 IOC 容器范围内都能共享该实例:所有后续的 getBean() 调用和 Bean 引用都将返回这个唯一的 Bean 实例.该作用域被称为 singleton, 它是所有 Bean 的默认作用域。
<bean id="" class="" scope="singleton"></bean>
10classpath 扫描方式加载bean
①context:annotation-config
配置文件中直接输入context:annotation-config <!-- 启用注解设置-->
系统会直接自动引入该命名空间(该标签省去属性依赖的配置,还需要在配置文件中写bean,只不过是省去了bean中属性的注入和属性配置,,通过在类中的属性之上直接加注解就会自动依赖
)
IOC通过扫描classpath中的bean(类/组件),加载到IOC中并管理,不需要把bean显示配置到文件中。
@Component给类添加一个组件注解,意思是该类需要被ioc容器管理。
@Autowired,表示注入功能,默认是按照类型注入,如果有两个以上的类型就会出现异常,此时可用用 @Qualifier("userService"),指定需要注入那个bean
@Resource(name="userService"):表示注入功能需要指定要被注入的bean的ID。
②<context:component-scan base-package="包名"></context:component-scan>
:上下文组件扫描,自动扫描加载到ioc中去管理
代替context:annotation-config 功能,而且附带另外的功能,与@rescource 组合搭配一起使用.
标注在类之上
@Component(""):任何类需要被管理,都可以使用该注解,完全可以代替下面三个注解,下面三个注解只是为了标识分层。
@Controller(""):标识控制器
@Service(""):标识业务层
@Repository(""):标识持久层
11 spring配置文件加载外部属性文件
Spring2.5及以上版本中支持的配置方式(建议使用):
首先,引入context命名空间。
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
再次,在java/resourcs/
下创建dbConfig.properties
文件,输入数据库信息
jdbc.name=root...................................
然后,加载属性文件
<context:property-placeholder location="classpath:dbConfig.properties"></context:property-placeholder>
最后再加载配置文件;
加载配置文件的两种方式详见本文:
12 配置druid数据源(数据库连接池)属性文件
实际开发的开发过程中与mybitis整合时,一般不用mybitis自带的数据库连接池,需要引入外部数据源.
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!-- 创建数据源 -->
<bean
id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<!-- 配置数据库连接基本信息 -->
<property
name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- ******配置数据库连接池相关信息******* -->
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="5" />
<property name="minIdle" value="2" />
<property name="maxActive" value="10" />
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="10000" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="testWhileIdle" value="true" />
<!-- 这里建议配置为TRUE,防止取到的连接不可用 -->
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="false" />
<!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize"
value="20" />
<!-- 这里配置提交方式,默认就是TRUE,可以不用配置 -->
<property name="defaultAutoCommit" value="true" />
<!-- 验证连接有效与否的SQL,不同的数据配置不同 -->
<property name="validationQuery" value="select 1" />
</bean>