Spring5框架(1)
一:什么是Spring?
Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。
◆目的:解决企业应用开发的复杂性
◆功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
◆范围:任何Java应用
Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。
下载使用Spring的开发包
官网:http://spring.io/
下载地址:
http://repo.springsource.org/libs-release-local/org/springframework/spring
特别说明:
spring5版本是用 jdk8编写的,所以要求我们的 jdk版本是 8及以上。 同时 tomcat的版本要求 8.5及 以上。
二:Spring的优势?
1.方便解耦,简化开发
通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造 成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可 以更专注于上层的应用。
2.AOP 编程的支持
通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付。
声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理, 提高开发效率和质量。
3.方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可 做的事情。
4.方便集成各种优秀框架
Spring 可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz 等)的直接支持。
5.降低 JavaEE API 的使用难度
Spring 对 JavaEE API(如 JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些 API 的 使用难度大为降低。
6.Java 源码是经典学习范例
Spring 的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对 Java 设计模式灵活运用以 及对 Java 技术的高深造诣。它的源代码无意是 Java 技术的最佳实践的范例。
三:结构?
四:程序的耦合和解耦?
4.1
package com.xy.domain;import com.xy.factory.BeanFactory;
import com.xy.service.AccountService;/*** 模拟一个表现层,用于调用业务层*/
public class Client {public static void main(String[] args) {
// AccountService accountService=new AccountServiceImpl();AccountService accountService= (AccountService) BeanFactory.getBean("accountService");accountService.saveAccount();}
}
上面的代码表示:
业务层调用持 久层,并 且此时业 务层在依 赖持久层 的接口和实 现类。如 果此时没 有持久层 实现类, 编译 将不能通过。这种编译期依赖关系,应该在我们开发中杜绝。我们需要优化代码解决。
再比如:
早期我们的 JDBC操作,注册驱动时,我们为什么不使用 DriverManager的 register方法,而是采 用 Class.forName的方式?
public class JdbcDemo1 {
/**
* @Version 1.0
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//1.注册驱动
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
//3.获取预处理 sql语句对象
//4.获取结果集
//5.遍历结果集
}
}
原因就是:
我们的类依赖了数据库的具体驱动类(MySQL),如果这时候更换了数据库品牌(比如 Oracle),需要 修改源码来重新数据库驱动。这显然不是我们想要的。
当是我们讲解 jdbc时,是通过反射来注册驱动的,代码如下:
Class.forName("com.mysql.jdbc.Driver");//此处只是一个字符串
此时的好处是,我们的类中不再依赖具体的驱动类,此时就算删除 mysql 的驱动 jar 包,依然可以编译(运 行就不要想了,没有驱动不可能运行成功的)。
同时,也产生了一个新的问题,mysql驱动的全限定类名字符串是在 java类中写死的,一旦要改还是要修改 源码。
解决这个问题也很简单,使用配置文件配置。
4.2工厂模式解耦
在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的 方法通过读取配置文件,把这些对象创建出来并存起来 。在接下来的使用的时候,直接拿过来用就好了。
那么,这个读取配置文件,创建和获取三层对象的类就是工厂。
4.3控制反转-Inversion Of Control
解耦的思路有 2个问题:
1、存哪去?
分析:由于我们是很多对象,肯定要找个集合来存。这时候有 Map和 List供选择。
到底选 Map还是 List就看我们有没有查找需求。有查找需求,选 Map。
所以我们的答案就是
在应用加载时,创建一个 Map,用于存放三层对象。
我们把这个 map称之为容器。
2、还是没解释什么是工厂?
工厂就是负责给我们从容器中获取指定对象的类。这时候我们获取对象的方式发生了改变。 原来:
我们在获取对象时,都是采用 new的方式。是主动的。
现在:
我们获取对象时,同时跟工厂要,有工厂为我们查找或者创建对象。是被动的。
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
五:IOC解耦案例
账户的业务层和持久层的依赖关系解决。
在开始 spring的配置之前,我们要先准备 一下环境。由于我们是使用 spring 解决依赖关系,并不是真正的要做增删改查操作,所以此时我们没必要写实体 类。并且我们在此处使用的是 java工程,不是 java web工程。
5.1创建业务层接口和实现类
package com.xy.service;/*** 业务层的接口,操作账户*/
public interface AccountService {/*** 模拟保存账户*/public void saveAccount();
}package com.xy.service.Impl;import com.xy.dao.AccountDao;
import com.xy.dao.impl.AccountDaoImpl;
import com.xy.factory.BeanFactory;
import com.xy.service.AccountService;/***账户的业务层实现类*/
public class AccountServiceImpl implements AccountService {
// private AccountDao accountDao=new AccountDaoImpl();private AccountDao accountDao= (AccountDao) BeanFactory.getBean("accountDao");public void saveAccount() {accountDao.saveAccount();}
}
5.2创建持久层接口和实现类
package com.xy.dao;/*** 持久层接口*/
public interface AccountDao {/*** 模拟保存账户*/public void saveAccount();
}package com.xy.dao.impl;import com.xy.dao.AccountDao;public class AccountDaoImpl implements AccountDao {public void saveAccount() {System.out.println("保存了账户");}
}
5.3XML文件配置
第一步:在pom.xml中导入必备的spring包。
第二步:在类的根路径下创建一个bean.xml文件。
第三步:给配置文件导入约束:
打开你的spring包的位置:/spring-framework-5.1.6.RELEASE/docs/spring-framework-reference/core.html,找到以下
内容:
在bean.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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd">
第四步:让spring管理资源,在配置文件中配置service和dao:
<!--把对象的创建交给spring来管理--><bean id="accountService" class="com.xy.service.Impl.AccountServiceImpl"></bean><bean id="accountDao" class="com.xy.dao.impl.AccountDaoImpl"></bean>
第五步:测试:
package com.xy.domain;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xy.dao.AccountDao;
import com.xy.service.AccountService;
import com.xy.service.Impl.AccountServiceImpl;
import org.springframework.context.support.FileSystemXmlApplicationContext;/*** 模拟一个表现层,用于调用业务层*/
public class Client {/*** 获取spring的IOC容器,并根据id获取对象* @param args*/public static void main(String[] args) {//1.获取核心容器对象ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean.xml");//根据id获取Bean对象AccountService accountService= (AccountService) applicationContext.getBean("accountService");AccountDao accountDao=applicationContext.getBean("accountDao",AccountDao.class);System.out.println(accountService);System.out.println(accountDao);}
}
运行:
5.4spring 中工厂的类结构图
获取spring的Ioc核心容器,并根据id获取对象ApplicationContext的三个常用实现类:ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)AnnotationConfigApplicationContext:它是用于读取注解创建容器的,是明天的内容。核心容器的两个接口引发出的问题:ApplicationContext: 单例对象适用 采用此接口它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。BeanFactory: 多例对象使用它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。
5.5IOC 中 bean 标签和管理对象细节
作用:
用于配置对象让 spring来创建的。
默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
属性:
id:给对象在容器中提供一个唯一标识。用于获取对象。
class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
scope:指定对象的作用范围。
* singleton :默认值,单例的.
* prototype :多例的.
* request :WEB项目中,Spring创建一个 Bean的对象,将对象存入到 request域中. * session :WEB项目中,Spring创建一个 Bean的对象,将对象存入到 session域中.
* global session:WEB项目中,应用在 Portlet环境.如果没有 Portlet环境那么globalSession相当于 session.
init-method:指定类中的初始化方法名称。
destroy-method:指定类中销毁方法名称。
bean 的作用范围和生命周期:
Spring对bean的管理细节:1.创建bean的三种方式:
第一种方式:使用默 认无参构造函数
在默认情况下:
它会根据默认无参构造函数来创建类对象。如果 bean中没有默认无参构造函数,将会创建失败。
<bean id="accountService" class="com.xy.service.impl.AccountServiceImpl"></bean>
第二种:使用普通工厂中的方法创建对象(使用某个类中的方法创建对象),并存入spring容器:
模拟一个工厂:
package com.xy.factory;import com.xy.service.AccountService;
import com.xy.service.impl.AccountServiceImpl;public class testFactory {public AccountService getAccountService(){return new AccountServiceImpl();}
}
<bean id="testFactory" class="com.xy.factory.testFactory"></bean><bean id="getaccountService" factory-bean="testFactory" factory-method="getAccountService"></bean>
第三种:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器):
package com.xy.factory;import com.xy.service.AccountService;
import com.xy.service.impl.AccountServiceImpl;public class testSFactory {public static AccountService getAccountService(){return new AccountServiceImpl();}
}<bean id="getAccountService" class="com.xy.factory.testSFactory" factory-method="getAccountService" scope="prototype"init-method="init" destroy-method="destroy"></bean>
2.bean对象的三种范围
<!--beand的作用范围:默认是单例的bean的scope属性指定作用范围取值:singleton 单例的(默认值)prototype 多例的request 作用于web应用的请求范围session 作用于web应用的会话范围global-session 作用于集群环境的会话范围,当不是集群环境时它就是session-->
3.bean对象的生命周期
<!--bean的生命周期:单例对象:出生:当容器创建时对象出生存活:当容器存活时对象存活死亡:当容器死亡对象死亡多例对象:出生:使用对象时spring框架为我们创建存活:对象在使用过程中就一直活着死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收-->
六:依赖注入(DI)
<!--Spring的依赖注入依赖注入:Dependency InjectionIOCd的作用:降低程序间的耦合依赖关系的管理:以后交给Spring来维护在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明依赖关系的维护:就称之为依赖注入。依赖注入:能注入的数据有三类基本类型和String其他bean类型(在配置文件中或者注解配置过的bean)复杂类型、集合类型注入的方式有三种:1.使用构造函数2.使用set方法3.使用注解-->
6.1构造函数注入:
<!--1.构造函数注入使用的标签:constructor-arg标签出现的位置:bean标签的内部标签中的属性:type:用于指定要注入的数据类型,该数据类型也是构造函数中的参数类型index:用于给构造函数中的指定索引位置的参数赋值,索引位置从0开始name:用于给构造函数中的指定名称的参数赋值 常用value:用于提供基本类型和String类型的数据ref:用于指定其他的bean类型数据。它指的就是在Spring的IOC容器中出现过的bean对象优势:在获取bean对象时候,注入数据是必须的操作,否则对象无法创建成功劣势:改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供--><bean class="com.xy.service.impl.AccountServiceImpl" id="accountService"><constructor-arg name="name" value="test"></constructor-arg><constructor-arg name="age" value="19"></constructor-arg><constructor-arg name="birthday" ref="now"></constructor-arg></bean><!--配置一个日期对象--><bean class="java.util.Date" id="now"></bean>
创建构造函数:
import com.xy.service.AccountService;import java.util.Date;/*** 账户的业务层实现类*/
public class AccountServiceImpl implements AccountService {private String name;private Integer age;private Date birthday;public AccountServiceImpl(String name, Integer age, Date birthday) {this.name = name;this.age = age;this.birthday = birthday;}public void saveAccount(){System.out.println("service 中的saveAccount()方法执行"+name+",age"+age+",birthday"+birthday);}}
6.3SET方法注入
!--2.set方法注入 更常用的注入方式标签:property位置:bean标签内部属性:name:用来指定注入时所调用的set方法名称value:用于提供基本类型和String类型的数据ref:用于提供其它的bean类型数据优势:创建对象时,没有明确的限制,可以直接使用默认构造函数弊端:如果某个成员必须有值,则获取对象是有可能set方法没有执行-->
创建带有set方法的业务层实现类:
package com.xy.service.impl;import com.xy.service.AccountService;import java.util.Date;/*** 账户的业务层实现类*/
public class AccountServiceImpl1 implements AccountService {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 saveAccount(){System.out.println("service 中的saveAccount()方法执行"+name+",age"+age+",birthday"+birthday);}}
<bean class="com.xy.service.impl.AccountServiceImpl1" id="accountService1"><property name="name" value="test1"></property><property name="age" value="19"></property><property name="birthday" ref="now"></property></bean>
6.3使用注解注入
此种方式是通过在 xml中导入 p名称空间,使用 p:propertyName来注入数据,它的本质仍然是调用类中的 set方法实现注入功能。
6.4集合注入
<!--复杂类型、集合类型的注入用于给List结构集合注入的标签:List,array,set集合标签用于给Map结构集合注入的标签:map,props -->
创建带集合的业务层实现类:
package com.xy.service.impl;import com.xy.service.AccountService;import java.util.*;/*** 账户的业务层实现类*/
public class AccountServiceImpl2 implements AccountService {private String []myString;private List<String> myList;private Set<String> mySet;private Map<String,String> myMap;private Properties myProperties;public void setMyString(String[] myString) {this.myString = myString;}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 setMyProperties(Properties myProperties) {this.myProperties = myProperties;}public void saveAccount(){System.out.println(Arrays.toString(myString));System.out.println(myList);System.out.println(mySet);System.out.println(myMap);System.out.println(myProperties);}}
<bean class="com.xy.service.impl.AccountServiceImpl2" id="accountService2"><property name="myString"><array><value>A</value><value>B</value><value>C</value></array></property><property name="mySet"><set><value>A</value><value>B</value><value>C</value></set></property><property name="myList"><list><value>A</value><value>B</value><value>C</value></list></property><property name="myMap"><map><entry key="testA" value="AAA"></entry><entry key="testB" value="BBB"></entry><entry key="testC" value="CCC"></entry></map></property><property name="myProperties"><props><prop key="testA">AAA</prop><prop key="testB">BBB</prop><prop key="testC">CCC</prop></props></property></bean>
其他内容请浏览本博主其它博客。
网站