首先我们要理解框架是什么?框架跟类库有什么区别?
框架,框架其实是一个半成品,它对基础的代码进行了封装并提供相应的API,开发者在使用框架是直接调用封装好的api可以省去很多代码编写,从而提高工作效率和开发速度。 其组成部分: jar包、配置文件(全局+单元)、启动代码等。
类库,类库(Class Library),字面意思就是类的集合,是一个综合性的面向对象的可重用类型集合,这些类型包括:接口、抽象类和具体类。
如何学习框架? 对于框架的学习,我们应该要理解框架的理念以及要解决的问题、学习它的配置和调用方式(其实可以理解为如何套用)、按照套路编码。
Spring 是最受欢迎的企业级 Java 应用程序开发框架,是为了解决企业应用程序开发复杂性而创建的。
Spring 框架是一个开源的 Java 平台,它最初是由 Rod Johnson 编写的,并且于 2003 年 6 月首次在 Apache 2.0 许可下发布。
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。Spring使用基本的JavaBean来完成以前只可能由EJB(Enterprise Java Bean)完成的事情。
Spring 框架的核心特性是可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践。
1.放便解耦,简单开发 通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
2.Aop 编程支持 通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
3.声明事务的支持 在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
4.方便程序的测试 可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。
5.方便框架的集合 Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供 了对各种优秀框架(如Struts、Hibernate、Hessian、 Quartz) 等的直接支持。
6.降低开发难度 Spring对很多难用的Java EE API (如JDBC, JavaMail, 远程调用等)提供了一-个薄薄的封装层, 通过Spring的简易封装,这些Java EE API的使用难度大为降低。
控制反转(IoC):即Inversion of Control。举例来说,在以前的项目中,要想调用一个类中的普通方法,则必须创建这个类的实例,再通过这个实例来调用其方法。而在Spring中,你不必再使用这种形式来创建对象,具体过程都交由Spring进行配置来实现。
面向切面编程(AOP):aop是一种编程技术,它允许程序员对横切关注点或横切典型的职责分界线的行为(例如日志和事务管理)进行模块化。AOP 的核心构造是切面,它将那些影响多个类的行为封装到可重用的模块中。
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
spring-beans : ioc 实现,配置文件的访问、创建和管理
SpEL : spring的表达式支持
Aspects: 对AspectJ框架的支持
instrumentation: 字节码操作
messaging : 对消息服务的支持
transactions : 事务支持
JDBC : spring对JDBC的封装
ORM : spring对于ORM框架的支持
web : 对于web开发的支持
核心理念: IoC inversion of control 控制反转 / DI dependency injection 依赖注入
控制权从调用的类转换到spring容器,由spring来实例化对象及依赖注入
1) 创建对象 2)依赖注入 ( 为属性填入实例)
建一个简单的登录项目吧。
之前已经配置好了maven,在此就不多说。
在pom.xml加入依赖。自动导入jar包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.0.RELEASE</version> </dependency>DAO
public interface UserDAO { String login(String username, String password); }DAO实现
public class UserDAOImpl implements UserDAO { @Override public String login(String username, String password) { //暂时不与数据库交互,直接返回字符串测试是否执行 return "UserDAOImpl执行了。。。"; } }Service
public interface UserService { String login(String username, String password); }Service实现
public class UserServiceImpl implements UserService { //此时我们声明UserDAO,但并不创建对象 private UserDAO userDAO; @Override public String login(String username, String password) { //直接通过声明调用方法 return userDAO.login(username,password); } //创建setter方法 public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } }Controller
public class UserController { //声明userService private UserService userService; public String login(String username,String password){ //通过声明直接调用方法 return userService.login(username,password); } //创建setter方法 public void setUserService(UserService userService) { this.userService = userService; } }创建applicationContext.xml。通过bean标签来引入具体的类。注意引入的是实现类,满足面向接口编程。
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--通过setter注入--> <bean id="userController" class="com.alter.spring.controller.UserController"> <!--通过ref引入已存在的bean--> <property name="userService" ref="userService"/> </bean> <bean id="userService" class="com.alter.spring.service.impl.UserServiceImpl"> <property name="userDAO" ref="userDAO"/> </bean> <bean id="userDAO" class="com.alter.spring.dao.impl.UserDAOImpl"/> </beans>运行之后打印如下: 从这个例子可以看出,spring框架通过xml配置来获得实例,我们可以将Ioc理解成一个容器,通过xml配置来获得bean实例,并将这些实例保存在容器中。 但是得到实例之后里面的属性又如何注入呢?bean实例化配置只有这种方法吗? 下面我们就讲一讲xml其他的配置方式。
通过value 注入基本类型 首先我们在controller加入一个基本类型的属性age
public class UserController { //基本属性age private String age; //setter方法 public void setAge(String age) { this.age = age; } ... }xml配置:
<bean id="userDAO" class="com.alter.spring.dao.impl.UserDAOImpl"> <!-- 通过value配置基本属性--> <property name="age" value="18" /> </bean>ref 注入已有的bean java类:
public class UserController { //声明userservice private UserService userService; //setter方法 public void setUserService(UserService userService) { this.userService = userService; } ... }xml配置:
<bean id="userController" class="com.alter.spring.controller.UserController"> <!-- 通过ref配置容器中已存在的bean--> <property name="userService" ref="userService"/> </bean>List \ Set \ Map等复杂类型配置 java配置
public class UserController { //声明list集合 private List<String> list; //创建setter方法 public void setList(List<String> list) { this.list = list; } //声明map集合 private Map<String, String> map; //创建setter方法 public void setMap(Map<String, String> map) { this.map = map; } //声明set集合 private Set<Integer> set; //创建setter方法 public void setSet(Set<Integer> set) { this.set = set; } ... }xml配置
<bean id="userDAO" class="com.alter.spring.controller.UserController"> <!-- 通过name指定List属性名,value配置具体的属性值--> <property name="list"> <list> <value>manager</value> <value>farmer</value> <value>driver</value> </list> </property> <!-- 通过name指定Map属性名,<entry>配置具体的属性值--> <property name="map"> <map> <entry key="pig" value="pink"/> <entry key="cat" value="orange"/> </map> </property> <!-- 通过name指定Set属性名,value配置具体的属性值--> <property name="set" > <set> <value>2</value> </set> </property> </bean>最后我们验证这些属性是否配置成功,在login方法中加入输出语句。
public class UserController{ ... public String login(String username,String password){ System.out.println("age="+age); System.out.println("list="+list); System.out.println("map="+map); System.out.println("set="+set); return userService.login(username,password); } }这时IDEA打印如下,说明属性配置成功。
默认构造器实例化 上述的实例中,在xml文件中配置bean实例其实是调用指定类的默认的无参构造方法。(可以给定其有参构造,此时就会抛出异常,在此省略验证步骤)
静态工厂方法实例化
<!--用静态工厂方法创建一个connection作为springbean--> <bean id="connection" factory-method="getConnection" class="com.alter.spring.common.JDBCUtils"/> <!--某个类(JDBCUtils)的静态方法(getConnection),返回值作为bean-->工厂bean实例化
<!--工厂bean--> <bean id="holidayFactory" class="com.alter.spring.factory.HolidayFactory"/> <!--holidayBean--> <bean id="holiday" factory-bean="holidayFactory" factory-method="create"></bean> public class HolidayFactory { public Holiday create(){ return new Holiday(); } }Spring的FactoryBean接口实例化
一个类实现FactoryBean接口,实现其方法
配置之后,bean的实例为FactoryBean的getObject方法的返回值
public class CarFactory implements FactoryBean<Car> { @Override public Car getObject() throws Exception { return new Car(); } @Override public Class<?> getObjectType() { return Car.class; } } <bean id="car" class="com.alter.spring.factory.CarFactory"/><constructor-arg name index>
index : 用于指定要注入的数据给构造函数中指定索引位置的参数赋值,索引的位置时从0开始name(常用) : 用于指定给构造函数中指定名称的参数赋值设置 value ref list set
<bean id="userService" scope="singleton" class="com.alter.spring.injection.UserServiceImpl" > //可以使用name <constructor-arg name="userDAO" ref="userDAO"></constructor-arg> <constructor-arg name="serviceId" value="12306"/> <constructor-arg name="data" > //或者使用index <constructor-arg index="0" ref="userDAO"></constructor-arg> <constructor-arg index="1" value="12306"/> <constructor-arg index="2" > <list> <value>xiong</value> <value>nian</value> <value>haha</value> </list> </constructor-arg> </bean> public class UserServiceImpl implements UserService { private UserDAO userDAO; private int serviceId; private List<String> data; public UserServiceImpl(UserDAO userDAO,int serviceId,List<String> data){ this.userDAO = userDAO; this.serviceId=serviceId; this.data =data; }; }特点:在获取 bean 对象时,注入数据是必须的操作,否则无法操作成功
弊端:改变了 bean 对象的实例化方式,使我们在用不到这些数据的情况下也必须提供带参构造函数,因此开发中较少使用此方法,除非避无可避
在bean配置上写init-method和destroy-method
<bean id="cycle" class="com.alter.spring.lifeCycle.Cycle" init-method="beginning" destroy-method="ending"/> public class Cycle { public void beginning(){ System.out.println("开始"); } public void ending(){ System.out.println("结束"); } }实现InitializingBean和DisposableBean及其方法
<bean id="cycle2" class="com.alter.spring.lifeCycle.Cycle2"/> //因为实现了接口,spring可以识别,所以不需要写intit和destroy public class Cycle2 implements InitializingBean, DisposableBean { @Override public void afterPropertiesSet() throws Exception { System.out.println("开始...."); } @Override public void destroy() throws Exception { System.out.println("结束了...."); } }