文章目录
(一) Spring概述
1. 是什么
Spring是分层的Java SE/EE 应用full-stack轻量级开源框架,以Ioc(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架。
IOC的解耦只能削减计算机的耦合,不能消除,只能降低耦合。
2. 发展历程
1997年IBM提出了EJB的思想
1998年,SUN制定开发标准规范EJB1. 0
1999年,EJB1.1发布
2001年,EJB2. 0发布
2003年,EJR2. 1发布
2006年,EJB3. 0发布
Rod Johnson (spring 之父)
Expert 0ne-to-0ne J2EE Design and Development (2002)
阐述了J2EE使用EJB开发设计的优点及解决方案
Expert 0ne-to-0ne J2EE Development without E JB (2004)
阐述了J2EE开发不使用EJB的解决方式(Spring 雏形)
2017年9月份发布了spring 的最新版本spring 5. 0通用版(GA)
3. 优势
(1)方便解耦,简化开发
通过Spring提供IoC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
(2)AOP编程的支持
通过Spring的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
(3)声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务管理,提高开发效率和质量。
(4)方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。
(5)方便集成各种优秀框架
Spring可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的直接支持。
(6)降低JavaEE API的使用难度
Spring对JavaEE API(如JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些API的使用难度大为降低。
(7)Java源码是经典的学习范例
Spring的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及Java技术的高深造诣。它的源代码无意是Java技术最佳实践范例
4. 体系结构
5. 程序的耦合
(1)耦合和解耦
耦合:程序间的依赖关系;包括:类之间的依赖;方法之间的依赖;
解耦:降低程序间的依赖关系
[实际开发中:应该做到:编译期不依赖,运行时才依赖]
(2)解耦的思路:
第一步:使用反射来创建对象,而避免使用new关键字。
第二步:通过读取配置文件来获取要创建的对象全限定类名
(3)工厂类和配置文件
一个创建Bean(可重用组件)对象的工厂
JavaBean>实体类
它就是创建service和dao对象的。
第一个:需要一个配置文件来配置我们的service和dao
配置的内容:唯一标志=全限定类名(key=value)
第二个:通过读取配置文件中配置的内容,反射创建对象。
配置文件可以是xml也可以是properties
(二)spring的IOC解决程序耦合
spring的IOC不能实现数据库增删改查,也不能实现表现层的请求参数封装,甚至也不能接受请求,但是它可以解耦,降低程序间的依赖关系。
由于我们是使用spring解决依赖关系,并不是真正要做到增删改查的操作,所以此时我们没必要写实体类,并且我们在此处使用的java工程,不是java. Web工程。
官网下载开发包
【application的Ioc核心容器,根据id获取对象】
//模拟一个表现层,用于调用业务层
public class Client {
public static void main(String[] args) {
//1.获取核心容器对象
ApplicationContext ac = new ClasspathXmlApplicationContext(configLocation:"bean.xml");
//ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\Users\\zhy\\Desktop\\bean.xml");
//2.很据i获取Bean对象
IAccountService as = (IAccountService)ac.getBean( "accountService");
IAccountDao adao = ac.getBean(name:"accountDao",IAccountDao.class);
System.out.print(as);
System.out.print(adao);
as.saveAccount();
}
1.ApplicationContext的三个常用实现类:
ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下,不在的话,加载不了。(更常用)
FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
AnnotationConfigApplicationContext:它是用于读取注解创建容器的
2.核心容器的两个接口引发的问题
(1)ApplicationContext:(单例对象适用)(实际开发中,采用此接口更常用)
它在构建核心容器时,创建对象采取的策略是采用立即加载的方式,也就是说,只要一读取完配置文件马上就创建配置文件中的配置的对象。
(2)BeanFactory:(多例对象适用)
它在创建核心容器时,创建对象采取的策略是采用延迟加载的方式,什么时候根据id获取对象了,什么时候才能真正的创建对象。
把对象的创建交给spring来管理
3.spring对bean的管理细节
(1)创建bean的三种方式
第一种方式:使用默认构造函数创建
在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。
<bean id="accountService" class="com.dynamic.service.impl.AccountServiceImpl"></bean>
id:取值; class:反射
第二种方式:使用普通工厂的方法创建对象(使用某个类中的方法创建对象,并存入spring容器中 )
<bean id="instanceFactory" class="com.dynamic.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
<bean id="accountService" class="com.dynamic.factory.StaticFactory" factory-method="getAccountService"></bean>
(2)bean对象的作用范围
bean标签的scope属性:
作用:用于指定bean的作用范围
取值:(常用的单例和多例的)
singleton:单例(默认值)
prototype:多例的
request:作用于web应用的请求范围
session:作用域web应用的会话范围
global-session:作用域集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session
如下图:
(3)Bean对象的声明周期
单例对象
出生:当容器创建时对象出生
活着:只要容器在,对象一直活着
死亡:容器销毁,对象消亡
【总结:单例对象的声明周期和容器相同】
多例对象
出生:当我们使用对象时spring框架为我们创建
活着:对象只要是在使用过程中就一直活着
死亡:当对象长时间不用,且没有别的对象引用时,由java的垃圾回收机制回收
4.Spring中的依赖注入
依赖注入:DI(Dependency Injection)
(1)是什么
IOC的可以,降低程序间的耦合(依赖关系),依赖关系,以后都交给spring来维护。在当前类需要用到其他类的对象,由spring来为我们提供,我们只需要在配置文件中说明依赖关系的维护:就称之为依赖注入(DI)。
(2)依赖注入:能注入的数据有三类
基本类型和string、其他bean类型(在配置文件中或者注解配置过的bean)、复杂类型/集合类型
(3)注入的方式:有三种
①第一种:使用构造函数提供
使用的标签:constructor-arg
标签内出现的位置:bean标签的内部
标签中的属性:
Type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某些参数的类型
Index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
Name:用于指定给构造函数中指定名称的参数赋值
【以上三个用于给指定构造函数中那个参数赋值】
Value:用于提供基本类型和string类型的数据
Ref:用于指定其他的bean类型数据,它指的就是在spring的Ioc核心容器中出现过的bean对象
【以上两种比较常用】
优势:在获取bean对象时,注入数据是必须的操作,否则对象无法创建。
弊端:改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。
示例:
AccountServiceImpl.java写入如下代码:
//账户的业务层实现类
public class AccountServiceImpl implements IAccountService {
//如果是经常变化的数据,并不适用于注入的方式
private String name;
private Integer age;
private Date birthday ;
public AccountServiceImpl(String nane ,Integer age , Date bi rthday){
this .hame = name ;
this.age = age ;
this.birthday = birthday;
}
public void saveAccount(){
System.out.print in(”service中的savelccount方法执行了... "nane+","age+","+birthday) ;
}
}
test类中写入如下信息:
<bean id="accountService"class="com.dynamic.service.imp1.Ac
countserviceImpl">
<constructor-arg name="name" value="test"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" value="now"></constructor-arg>
</bean>
<!-- 配置一个日期对象-->
<bean id="now" class="java.util.Date"></bean>
模拟一个表现层用户调用业务层:
public class Client {
public static void main(String[] args) {
//1.获取核心容器对象
ApplicationContext ac = new ClasspathXmlApplicationContext(configLocation:"bean.xml");
//2.很据i获取Bean对象
IAccountService as = (IAccountService)ac.getBean( "accountService");
as.saveAccount();
}
② 第二种:使用set方法提供(更常用)
涉及的标签:property
出现的位置:bean标签的内部
标签的属性:
Name:用于指定注入时所调用的Set方法名称
Value:用于提供基本类型和string类型的数据
Ref:用于指定其他的bean类型数据,它指的就是在spring的Ioc核心容器中出现过的bean对象
优势:创建对象时没有明确的限制,可以直接使用默认构造函数。
弊端:如果某个成员必须有值,则获取对象是有可能set方法没有执行。
AccountServiceImpl.java写入如下代码:
//账户的业务层实现类
public class AccountServiceImpl2
inplements IAccountService {
//如果是经常变化的数据,并不适用于往入的方式
private String name;
private Integer age;
private Date birthday;
public void setName(String name) {
this.name = name;
}
public woid setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public void setAccount() {System.out printIn("service
中的saveccount方法执行了..."+name+","age+","+birthday);
测试类中写入如下文件:
<bean id="accountService2"class="com.dynamic.service.imp1.Ac
countserviceImpl2">
<property name="name" value="test"></property>
<property name="age" value="18"></property>
<property name="birthday" value="now"></property>
</bean>
<!-- 配置一个日期对象-->
<bean id="now" class="java.util.Date"></bean>
模拟一个表现层用户调用业务层:
public class Client {
public static void main(String[] args) {
//1.获取核心容器对象
ApplicationContext ac = new ClasspathXmlApplicationContext(configLocation:"bean.xml");
//2.很据i获取Bean对象
IAccountService as = (IAccountService)ac.getBean( "accountService2");
as.saveAccount();
}
③ 第三种:使用注解提供
复杂类型/集合类型的注入
用于给List结构集合注入的标签:
List array set
用于给map结构集合注入的标签:
Map props
结构相同,标签可以互换。
//账户的业务层实现类
public class AccountServiceImp3 implements IAccount Service {
private string[] myStrs;
private List<String> mylist;
private Set<String> mySet ;
private Map<String,String> myMap;
private Properties myProp;
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 saveAccount(){
System.out.println(Arrays toString(myStrs));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap);
System.out.println(myProps);
}
}
模拟一个表现层用户调用业务层:
public class Client {
public static void main(String[] args) {
//1.获取核心容器对象
ApplicationContext ac = new ClasspathXmlApplicationContext(configLocation:"bean.xml");
//2.很据i获取Bean对象
IAccountService as = (IAccountService)ac.getBean( "accountService3");
as.saveAccount();
}
【思考】
Spring的IOC到底能解决什么问题?如何搭建出来Spring基于XML和IOC的开发环境?如何实现类之间的依赖,使用Sping注入?
5.基于注解的IOC配置
学习基于注解的IOC配置,首先要知道,注解配置和xml配置要实现的功能都是一样的,都是要降低程序间的耦合,只是配置的形式不一样。
(1)基于xml的配置
//导入jar包
<packaging>jar</packaging>
//导spring框架
<dependencies>
<dependency>
<groupId>org springframework</groupId>
<artifactld>spring-context</artifactId>
sversion>5.0.2. RELEASE</vers ion2
</dependency>
</dependencies>
在resource下新建一个bean.xml
<!—导入约束-->
<?xmlversion="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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!—把对象的创建交给Spring来管理-->
<bean id="accountService"class="com.dynamic.service.impl.AccountServiceImpl">
</bean>
<bean id="accountDao"class="com.dynamic.dao.imp.AccountDaoImpl"></bean>
</beans>
表现层Client:
(2)基于注解的配置
//账户的业务层实现类
//曾经XML的配置:
<bean id "accountService" class= "com. dynamic.service. impl .AccountServiceImpl”
scope= "” init method= "”des troy-method= "">
<property name="" value="" ref=""></property>
</bean>
①用于创建对象的
他们的作用就和在XmL配置文件中编写一个<bean>标签实现的功能是一样的
Component :
作用:用于把当前类对象存入spring容器中
属性:value用于指定bean的id.当我们不写时,它的默认值是当前 类名,且首宇母改小写。
Controller:一般用在表现层
Service: 一般用在务层
Repository:一般用在持久层
以上三个注解他们的作用和属性与Component是一模样。
他们三个是spring框架为我们提共明确的三层使用的注解,使我们的三层对象更加清晰
②用于注入数据的
他们的作用就和在xml配置文件的bean标签中写一个<property>签的作用是样的
Astowired:
作用:自动按照类型注。只要容器中有哇一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
如果ioc容器中没有任何bean的类型和要注人的变量类型配,则报错。
如果Ioc容器中有多个类型的匹配时,
出现位置可以是变量上,也可以是方法上
细节:在使用注解注人时,set方法就不是必须的了.
Qualifier:
作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单使用。但是在给方法参数注人时可以
属性:value用于指定注bean的id
Resource
作用:直接按照bean的id注入。它可以独立使用
属性:name用于指定bean的id。
【以上三个】注入都只能注人其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
另外,集合类型的注入只能通过XML来实现。
Value
作用:用于注入基本类型和String类型的数据
属性:
value用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
SpEL的写法,${表达式}
用于改变作用范围的
他们的的作用就和在bean标签中使用scope的作用是一样的
Scope
作用:用于指定bean的作用范围
属性:value:指定范围的取值。常用取值:singleton,prototype
和生命周期相关
他们的的作用就和在bean标签中使用init-mehod和destory-methode的作用是一样的
PreDestroy
作用:用于指定销毁方法
PostConstruct
作用:用于指定初始化方法
是谁的el,就去谁规定的位置取值,看{}符号写的位置。如果{}写在jsp文件中,就是jsp的el表达式,一定会去spel获取数据,如果写在spring的配置文件或者注解中,就是Spring的el表达式,会去spring指定的位置取值,如果是写在mybaits的配置文件中,就去mybatis对应的位置取值
(3)其他配置;
如果把一个子类看成父类型,就只能调用父类型的方法,就close不来。
这时候需要把它看出自己,然后释放,就可以销毁了。
6. 基于XML的IOC,编写Spring的Ioc配置
[基于XML、注解的配置]
7. spring的新注解
三种配置:Xml(类是别人写好的,存在于jar包中)、注解(类是自己写的)、Xml和注解结合(根据情况选择)
【配置方式的汇总】
(三)spring中的AOP
未完待续…