目录基本介绍Spring什么是Spring核心架构特点控制反转(或依赖注入)控制反转(IOC)依赖注入(DI)IOC 实操三种配置方式Bean元素的常用属性bean 的要求常见属性日期类型注入ref引用复杂类型注入spring与web项目集成创建监听器配置监听器测试完整代码pom.xml 配置实体类 entityHello.javaPerson.javaStudent.javaWorker.java工具类Demo.javaIOC 容器管理spring.xmlspring-address.xml前端页面index.jsp
Spring 是一款目前主流的 Java EE 轻量级开源框架 ,是 Java 世界最为成功的框架之一。Spring 由“Spring 之父”Rod Johnson 提出并创立,其目的是用于简化 Java 企业级应用的开发难度和开发周期。
Spring 自诞生以来备受青睐,一直被广大开发人员作为 Java 企业级应用程序开发的首选。时至今日,Spring 俨然成为了 Java EE (J2EE)代名词,成为了构建 Java EE 应用的事实标准。
官网:https://spring.io/
Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。
高内聚,松藕合。
松藕合:减少模块与模块之间的依赖关系。(为了开发的可扩展性,需要降低这种依赖关系) -> 解耦
藕合:两个紧密关系非常密切
Spring 框架是一个分层的、面向切面的 Java 应用程序的一站式轻量级解决方案,它是 Spring 技术栈的核心和基础,是为了解决企业级应用开发的复杂性而创建的。
简单来说,Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。
介于SpringMVC与Mybatis之间的中间层框架,作用:承上启下,相当于粘合剂
核心 |
描述 |
IOC |
Inverse of Control 的简写,译为“控制反转”,指把创建对象过程交给 Spring 进行管理。 |
AOP |
Aspect Oriented Programming 的简写,译为“面向切面编程”。 AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。 |
Spring 是一种基于 Bean(豆子) 的编程技术,它深刻地改变着 Java 开发世界。Spring 使用简单、基本的 Java Bean 来完成以前只有 EJB 才能完成的工作,使得很多复杂的代码变得优雅和简洁,避免了 EJB 臃肿、低效的开发模式,极大的方便项目的后期维护、升级和扩展。
在实际开发中,服务器端应用程序通常采用三层体系架构,分别为表现层(web)、业务逻辑层(service)、持久层(dao)。
表现层;业务逻辑层;数据访问层
Spring 致力于 Java EE 应用各层的解决方案,对每一层都提供了技术支持。
在表现层提供了对 Spring MVC、Struts2 等框架的整合;
在业务逻辑层提供了管理 事务(ACID)和记录日志的功能;
在持久层还可以整合 MyBatis、Hibernate 和 JdbcTemplate 等技术,对数据库进行访问。
这充分地体现了 Spring 是一个全面的解决方案,对于那些已经有较好解决方案的领域,Spring 绝不做重复的事情。(Spring 不会参与其他的领域,只专注于自己的事情:整合)
事务是什么?
ACID:一致性、原子性、隔离性、持久性
日志干什么的?
用来记录 调用的每个方法,知道谁是谁调的,什么时候调的
如果系统中的 数据被泄露,就可以通过查看日志来了解是谁搞出去的,什么时候搞出去的,从哪个电脑搞出去的。
从设计上看,Spring 框架给予了 Java 程序员更高的自由度,对业界的常见问题也提供了良好的解决方案,因此在开源社区受到了广泛的欢迎,并且被大部分公司作为 Java 项目开发的首选框架。
Spring Core:提供依赖注入和Bean管理功能,主要组件是 BeanFactory(豆子工厂:用于生产,需要原料),它使用控制反转模式 将应用程序配置和依赖规范与实际的应用代码分开;
Spring Context:扩展了BeanFactory的概念,增加了对国际化、事件传播,以及验证等的支持,此外还提供了许多企业服务及对模版框架集成的支持;(上下文)
Spring Web:建立于Context模块之上,提供了一个适合于Web应用的上下文。另外,这个模块还提供了一些面向服务支持,也提供了Spring和其它Web框架的集成;
Spring Web MVC:是一个全功能的构建 Web 应用程序的 MVC 实现,容纳了大量视图技术,如 JSP、Velocity、POI等;(核心 jar包)
Spring AOP:为Spring容器管理的对象提供了对面向切面编程的支持;
Spring DAO:该层封装了对数据库的访问,并且处理了其抛出的错误消息,同时还基于AOP模块提供了事务管理;
Spring ORM:Spring支持多种ORM框架(Mybatis、Hibernate),简化了数据库操作。
方便解耦,简化开发
Spring 就是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 管理。
方便集成各种优秀框架
Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis 等)的直接支持。
降低 Java EE API 的使用难度
Spring 对 Java EE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等)都提供了封装,使这些 API 应用的难度大大降低。
方便程序的测试
Spring 支持 JUnit4,可以通过注解方便地测试 Spring 程序。
AOP 编程的支持
Spring 提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能。
声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无须手动编程。
在传统的 Java 应用中,一个类想要调用另一个类中的属性或方法,通常会先在其代码中通过 new Object() 的方式将后者的对象创建出来,然后才能实现属性或方法的调用。为了方便理解和描述,我们可以将前者称为“调用者”,将后者称为“被调用者”。也就是说,调用者掌握着被调用者对象创建的控制权。
但在 Spring 应用中,Java 对象创建的控制权是掌握在 IoC 容器手里的,其大致步骤如下。
开发人员通过 XML 配置文件、注解、Java 配置类等方式,对 Java 对象进行定义,例如在 XML 配置文件中使用
Spring 启动时,IoC 容器会自动根据对象定义,将这些对象创建并管理起来。这些被 IoC 容器创建并管理的对象被称为 Spring Bean。
当我们想要使用某个 Bean 时,可以直接从 IoC 容器中获取(例如通过 ApplicationContext 的 getBean() 方法),而不需要手动通过代码(例如 new Obejct() 的方式)创建。
//传统 调用属性或方法
classA{
...
}
classB{ //B是调用者,A是 被调用者。(创建关系由我们自己维护 ->主动权掌握在 程序员手中)
main ...(){
Aa=newA();
a.set...;
a.init();
}
}
//Spring 的IOC容器 自动调用
classA{
...
}
classB{
main ...(){
//Spring 框架来创建 IOC容器来管理对象的创建过程
BeanFactory->Bean
}
}
IoC 带来的最大改变不是代码层面的,而是从 思想层面 上发生了主从换位的改变。原本调用者是主动的一方,它想要使用什么资源就会主动出击,自己创建;但在 Spring 应用中,IoC 容器掌握着主动权,调用者则变成了被动的一方,被动的等待 IoC 容器创建它所需要的对象(Bean)。
这个过程在职责层面发生了控制权的反转,把原本调用者通过代码实现的对象的创建,反转给 IoC 容器来帮忙实现,因此我们将这个过程称为 Spring 的“控制反转”。
总的来说,控制反转(IoC=Inversion of Control)IoC,用白话来讲,就是由容器控制程序之间的(依赖)关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在:(依赖)控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。
在面向对象中,对象和对象之间是存在一种叫做“依赖”的关系。简单来说,依赖关系就是在一个对象中需要用到另外一个对象,即对象中存在一个属性,该属性是另外一个类的对象。
例如,有一个名为 UserBizImpl 的 Java 类,它的代码如下。
//dao 层
interfaceUserDao{
List
}
//接口
classUserDaoImplimplementsUserDao{
List
...
}
}
//biz 层
interfaceUserBiz{
List
}
//biz 实现接口
classUserBizImplimplementsUserBiz{
//Biz 层需要 依赖于Dao层的接口(自己手动创建 依赖关系)
//private UserDao userDao = new UserDaoImpl();//UserDao 作为一个属性被调用,实际上是一个具体的类
//DI 依赖注入的关系
privateUserDaouserDao;//不做对象的 初始化
//需要提供 get、set方法,提供注入的入口
List
returnuserDao.queryUser();//实际上调用的是 UserDao 的方法
}
}
从代码可以看出,UserBizImpl中存在一个 userDao的对象,此时我们就可以说 UserBizImpl 的对象依赖于对象 userDao。而依赖注入就是就是基于这种“依赖关系”而产生的。
只有 有关系,才能被注入。
控制反转核心思想就是由 Spring 负责对象的创建。在对象创建过程中,Spring 会自动根据依赖关系,将它依赖的对象注入到当前对象中,这就是所谓的“依赖注入”。
即由Spring IOC容器动态的将某种依赖关系注入到组件之中
注入方式有很多,例如
构造器
注解
...
基于idea创建maven项目导入spring相关依赖(spring-core、spring-context)。
在resources目录右键 New -> XML Configuration File -> Spring Config。
//方式一:单独加载指定spring.xml配置文件
ApplicationContextac=newClassPathXmlApplicationContext("classpath:spring.xml");
//方式二:一次加载多个配置文件,数组方式
ApplicationContextac=newClassPathXmlApplicationContext(newString[]{"spring-mybatis.xml","spring-redis.xml"});
//方式三:使用*通配符方式
ApplicationContextac=newClassPathXmlApplicationContext("classpath:spring-*.xml");
属性 |
描述 |
id |
Bean 的唯一标识符,Spring 容器对 Bean 的配置和管理都通过该属性完成。id 的值必须以字母开始,可以使用字母、数字、下划线等符号。 |
name |
name 属性中可以为 Bean 指定多个名称,每个名称之间用逗号或分号隔开。Spring 容器可以通过 name 属性配置和管理容器中的 Bean。 |
class |
该属性指定了 Bean 的具体实现类,它必须是一个完整的类名,即类的全限定名。 |
scope |
用于设定 Bean 实例的作用域,属性值可以为 singleton(单例)、prototype(原型)、request、session 和 global Session。其默认值是 singleton |
constructor-org |
|
property |
|
ref |
|
value |
|
list |
用于封装 List 或数组类型的依赖注入 |
set |
用于封装 Set 类型的依赖注入 |
map |
用于封装 Map 类型的依赖注入 |
entry |
元素的子元素,用于设置一个键值对。其 key 属性指定字符串类型的键值,ref 或 value 子元素指定其值 |
init-method |
容器加载 Bean 时调用该方法,类似于 Servlet 中的 init() 方法 |
destory-method |
容器删除 Bean 时调用该方法,类似于 Servlet 中的 destroy() 方法。该方法只在 scope=singleton 时有效 |
lazy-init |
懒加载,值为 true,容器在首次请求时才会创建 Bean 实例;值为 false,容器在启动时创建 Bean 实例。该方法只在 scope=singleton 时有效 |
javaBean是拥有特殊写法的一类java,一个javabean必须满足三个条件:
属性必须私有化;
必须拥有一个无参的构造函数;
私有化的属性必须通过public类型的方法暴露给其它程序,并且方法的命名也必须遵守一定的命名规则。
id & name & class
scope
通过在Hello实体类中的无参构造方法中添加打印语句从而来验证是否是单例或者多例模式。
publicclassHello{
publicHello(){
System.out.println("new Hello()");
}
...
}
修改spring.xml中
Hello h11 = (Hello) ac.getBean("/a");
Hello h12 = (Hello) ac.getBean("b");
Hello h13 = (Hello) ac.getBean("c");
System.out.println(h11.getName());
System.out.println(h12.getName());
System.out.println(h13.getName());
abstract & parent
init-method
public class Student extends Person {
...
public void init() {
System.out.println("this is init method!");
}
...
}
constructor-arg
新增日期属性:
publicclassStudent{
privateDatebirthday;
....
publicDategetBirthday() {
returnbirthday;
}
publicvoidsetBirthday(Datebirthday) {
this.birthday=birthday;
}
}
利用SimpleDateFormat的构造方法注入:
创建外部spring配置文件spring-address.xml
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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.xsd http://www.springframework.org/schema/context " target="_blank">http://www.springframework.org/schema/context/spring-context-4.3.xsd"> 通过import标签引入到spring.xml中,并使用标签引入spring-address.xml文件中定义的bean。 ... 在Student实体类中新增List、Map、Properties、数组类型 publicclassStudent{ privateListlst; privateMapmap; privatePropertiesprop; privateString[] arr; .... } 在spring.xml文件中添加配置使用复杂类型注入 SpringListener.java packagecom.zking.spring01.util; importorg.springframework.context.ApplicationContext; importorg.springframework.context.support.ClassPathXmlApplicationContext; importjavax.servlet.ServletContext; importjavax.servlet.ServletContextEvent; importjavax.servlet.ServletContextListener; /** * Spring 监听器,完成 Spring上下文初始化操作 */ publicclassSpringListenerimplementsServletContextListener { privatestaticStringpath="spring.xml"; @Override publicvoidcontextInitialized(ServletContextEventsce) { System.out.println("初始化..."); //前往 web.xml 进行初始化 //1. 获取 ServletContext(application) ServletContextapplication=sce.getServletContext(); //2. 获取 web.xml 中配置的 context-parm 对应的 value 值 Stringlocation=application.getInitParameter("contextConfigLocation"); //3. 判断 location 是否为空 if("".equals(location)){ //如果获取的路径为null location=path; //将 path属性值赋值给location } //4. 初始化 Spring IOC容器(或 Spring Context上下文) ApplicationContextac=newClassPathXmlApplicationContext(location); //5. 将 Spring IOC容器存储到 application作用域中 SpringWebUtils.setContext(application,ac); } @Override publicvoidcontextDestroyed(ServletContextEventsce) { System.out.println("销毁..."); } } 创建SpringWebUtil工具类,将Spring上下文对象保存到Application作用域中。 SpringWebUtils.java packagecom.zking.spring01.util; importorg.springframework.context.ApplicationContext; importjavax.servlet.ServletContext; publicclassSpringWebUtils { publicSpringWebUtils() {} privatestaticfinalStringKEY="aaaa"; /** * 将 Spring IOC容器存储到 application作用域中 * @param application 作用域 * @param ac IOCor容器 */ publicstaticvoidsetContext(ServletContextapplication, ApplicationContextac) { application.setAttribute(KEY, ac); } /** * 从 application作用域中获取存储的 Spring IOC容器(根据 key值获取) * 在 存储之前已经实例化了 * @param application application作用域 * @return */ publicstaticApplicationContextgetContext(ServletContextapplication) { return (ApplicationContext)application.getAttribute(KEY); } } web.xml xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID"version="3.0"> index.jsp <%@pageimport="com.zking.spring01.util.SpringWebUtils"%> <%@pageimport="org.springframework.context.ApplicationContext"%> <%@pageimport="com.zking.spring01.entity.Student"%><%-- CreatedbyIntelliJIDEA. User:Youdabi Date:2023/3/6 Time:22:44 TochangethistemplateuseFile|Settings|FileTemplates. --%> <%@pagecontentType="text/html;charset=UTF-8"language="java"%> 复杂类型注入
spring与web项目集成
创建监听器
配置监听器
测试
<%
//java小脚本
//从application作用域中获取SpringIOC容器
ApplicationContextac = SpringWebUtils.getContext(application);
Studentstudent = ac.getBean("student",Student.class);
System.out.println(student);
%>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 " target="_blank">http://maven.apache.org/xsd/maven-4.0.0.xsd"> packagecom.zking.spring01.entity; publicclassHello { privateStringname; publicvoidquery(){ System.out.println("正在帮您查询数据,请稍等..."); } //Alt+Insert 快捷插入 publicStringgetName() { returnname; } publicvoidsetName(Stringname) { this.name=name; } publicHello() { System.out.println("new Hello()..."); } publicHello(Stringname) { this.name=name; } @Override publicStringtoString() { return"Hello{"+ "name='"+name+'\''+ '}'; } } packagecom.zking.spring01.entity; publicclassPerson { //人是一个抽象的概念。老师、学生、工人是具体的 privateStringname; publicStringgetName() { returnname; } publicvoidsetName(Stringname) { this.name=name; } publicPerson() { } publicPerson(Stringname) { this.name=name; } @Override publicStringtoString() { return"Person{"+ "name='"+name+'\''+ '}'; } } packagecom.zking.spring01.entity; importjava.util.Date; importjava.util.List; importjava.util.Map; importjava.util.Properties; publicclassStudentextendsPerson{ private Integersid; privateFloatscore; privateIntegerage; privateDatebirthDay; //复杂类型,并提供get set方法 privateMapmap; //Map 集合(键值对) privateListlist; //List 集合 privateString[] arr;//数组 privatePropertiesprops;// publicMapgetMap() { returnmap; } publicvoidsetMap(Mapmap) { this.map=map; } publicListgetList() { returnlist; } publicvoidsetList(Listlist) { this.list=list; } publicString[] getArr() { returnarr; } publicvoidsetArr(String[] arr) { this.arr=arr; } publicPropertiesgetProps() { returnprops; } publicvoidsetProps(Propertiesprops) { this.props=props; } //学生类 依赖于地址类 privateAddressaddress; //把地址类作为学生类的属性,实际上地址 是一个类 publicAddressgetAddress() { returnaddress; } publicvoidsetAddress(Addressaddress) { this.address=address; } publicDategetBirthDay() { returnbirthDay; } publicvoidsetBirthDay(DatebirthDay) { this.birthDay=birthDay; } publicIntegergetSid() { returnsid; } publicvoidsetSid(Integersid) { this.sid=sid; } publicFloatgetScore() { returnscore; } publicvoidsetScore(Floatscore) { this.score=score; } publicIntegergetAge() { returnage; } publicvoidsetAge(Integerage) { this.age=age; } publicStudent() { } publicStudent(Integersid, Floatscore, Integerage) { System.out.println("正在使用 Student中的有参"); this.sid=sid; this.score=score; this.age=age; } @Override publicStringtoString() { return"Student{"+ "sid="+sid+ ", score="+score+ ", age="+age+ '}'; } } packagecom.zking.spring01.entity; importjava.math.BigDecimal; publicclassWorkerextendsPerson{ privateIntegerwid; privateBigDecimalmoney; //BigDecimal 数字类型:工资 publicIntegergetWid() { returnwid; } publicvoidsetWid(Integerwid) { this.wid=wid; } publicBigDecimalgetMoney() { returnmoney; } publicvoidsetMoney(BigDecimalmoney) { this.money=money; } publicWorker() { } @Override publicStringtoString() { return"Worker{"+ "wid="+wid+ ", money="+money+ '}'; } } 方法测试,与结果的显示 packagecom.zking.spring01.util; importcom.zking.spring01.entity.Hello; importcom.zking.spring01.entity.Student; importcom.zking.spring01.entity.Worker; importorg.springframework.context.ApplicationContext; importorg.springframework.context.support.ClassPathXmlApplicationContext; importjava.util.Arrays; publicclassDemo { publicstaticvoidmain(String[] args){ //1.由程序员 自身控制对象的创建过程 Hellohello=newHello(); hello.setName("张三"); System.out.println(hello); //hello.out 回车:快捷输出 //2. 将程序员创建对象的权利 移交给 Spring的容器来管理,叫做:控制反转 //完成 对Spring IOC容器的 初始化 ApplicationContextac= newClassPathXmlApplicationContext("spring.xml"); //ac 就是 IOC容器 //从 IOC容器中 获取指定的 bean对象 Alt+回车:快捷导入对象 /* 1. 属性:id, name, class */ // Hello hello1 = ac.getBean("hello", Hello.class); // System.out.println(hello1.getName()); /* 2.scope 单例或多例 */ //scope="singleton" 单例模式:只在第一次初始化对象,后面是同一个实例对象 //scope="prototype" 多例模式:每次调用对象都初始化,每次都是全新的对象 /*Hello a = ac.getBean("a", Hello.class); Hello b = ac.getBean("b", Hello.class); Hello c = ac.getBean("c", Hello.class); System.out.println(a); System.out.println(b); System.out.println(c);*/ /* 3.abstract 抽象 ,parent 父类 */ // Student student = ac.getBean("student", Student.class); // System.out.println(student); // System.out.println(student.getName()); // // Worker worker = ac.getBean("worker", Worker.class); // System.out.println(worker); // System.out.println(worker.getName()); /* 4.init-method 初始化 */ // Hello a = ac.getBean("a", Hello.class);//实例化之后,调用 query方法 /* 5.constructor-arg 构造 */ // Student stu = ac.getBean("stu", Student.class); /* 日期类型的注入 */ Studentstudent=ac.getBean("student", Student.class); System.out.println(student.getBirthDay().toLocaleString()); /* ref 的引用 */ System.out.println(student.getAddress().getCity()); /* 复杂类型注入 */ //List集合 System.out.println(student.getList()); //Map 集合 System.out.println(student.getMap()); //数组 System.out.println(Arrays.toString(student.getArr()));//数组转字符串 //properties System.out.println(student.getProps()); } } xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans " target="_blank">http://www.springframework.org/schema/beans/spring-beans.xsd"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans " target="_blank">http://www.springframework.org/schema/beans/spring-beans.xsd"> <%@pageimport="com.zking.spring01.util.SpringWebUtils" %> <%@pageimport="org.springframework.context.ApplicationContext" %> <%@pageimport="com.zking.spring01.entity.Student" %><%-- CreatedbyIntelliJIDEA. User: Youdabi Date: 2023/3/6 Time: 22:44 TochangethistemplateuseFile|Settings|FileTemplates. --%> <%@pagecontentType="text/html;charset=UTF-8"language="java" %> 实体类 entity
Hello.java
Person.java
Student.java
Worker.java
工具类
Demo.java
IOC 容器管理
spring.xml
spring-address.xml
前端页面
index.jsp
<%
//java 小脚本
//从 application 作用域中获取 Spring IOC容器
ApplicationContextac=SpringWebUtils.getContext(application);
Studentstudent=ac.getBean("student", Student.class);
System.out.println(student);
%>