概述:
Spring特点:
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.降低Java EE API的使用难度
Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。
为了解决企业级开发的复杂度问题
可以让主业务逻辑不会应为其他技术问题受到阻碍,例如,主业务数据库的操作,其中数据库的连接,提交commit等操作,就属于交叉业务,如果数据库连接不成功就会受到阻碍,导致主业务进行不下去,耦合度较高;而spring 可以良好的解决这个问题
new User();像这种实例化一个对象的操作不在有程序员操作,有Spring管理(控制反转loC)
Spring 的核心是控制反转(IoC)和面向切面编程(AOP)
DI(依赖注入)
非侵入式:
Spring框架的API不会在业务逻辑上出现;由于业务逻辑没有Spring的API,所以有比Spring框架更好的框架,业务逻辑可以从立刻从Spring迁移到其他框架;
Spring框架是一个分层架构。Spring 由 20 多个模块组成,它们可以分为数据访问/集成(Data Access/Integration)、Web、面向切面编程(AOP, Aspects)、应用服务器设备管理(Instrumentation)、消息发送(Messaging)、核心容器(Core Container)和测试(Test)。
第一个Spring应用程序:
目的:测试控制反转:
如果需要更新这些依赖包的版本,在maven的仓库(repository)中搜索:https://mvnrepository.com/search?q=spring
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!--用于提示--> <modelVersion>4.0.0</modelVersion> <groupId>com.zy</groupId> <artifactId>工程8</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.17.RELEASE</version> </dependency> </dependencies> </project>
主要增加了 org.springframework:spring-context
依赖(单体引用直接4就可以了)
主要导入的jar包有(如过不使用maven,可以尝试自己导入相应的jar包)
4个核心包(beans、core、expression、context)和一个依赖包(commons.logging)
创建 Spring 配置文件
在 src/main/resources
目录下创建 spring-context.xml
(或者applicationContext.xml (其实名字可以任意))配置文件,从现在开始类的实例化工作交给 Spring 容器管理(IoC),配置文件如下:
<?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"> <bean id="userService" class="com.zy.service.impl.UserServiceImpl" /> //UserServiceImpl类自己实现 </beans>
-
<bean />
:用于定义一个实例对象。一个实例对应一个 bean 元素。 -
id
:该属性是 Bean 实例的唯一标识,程序通过 id 属性访问 Bean,Bean 与 Bean 间的依赖关系也是通过 id 属性关联的。 -
class
:指定该 Bean 所属的类,注意这里只能是类,不能是接口。
import com.zy.service.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { //获取Spring容器 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-context.xml"); //从Spring容器获取对象 UserService userService = (UserService) applicationContext.getBean("userService"); userService.test();//调用方法 } }
如果需要在spring实例化对象的时候自动装配属性
<?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"> <context:property-placeholder ignore-unresolvable="true" location="classpath:myshop.properties"/> //加载配置属性文件 <bean id="userService" class="com.zy.service.impl.UserServiceImpl"> <property name="name" value="zz"/> //其中的value,可以用 "${name}" 从加载的配置文件获去 </bean> <bean id="userService" class="com.zy.service.impl.UserServiceImpl"> <property name="xx"> //如果value是一个对象 <bean class="xx.xx.xx.xx"> //class 就是实例化对象的路径 <constructor-arg name="xx" value="xx"></constructor-arg> //如果实例化该对象需要加上构造参数 </bean> </property> </bean> </beans>
<bean id="userService",class=“com.zy.service.imp.UserServiceImpl”></bean>
相当于spring帮我们实例化了UserServiceImpl userService = new UserServiceImpl(); //所以class一定不能是接口,不然实例化不了;
目的:测试依赖注入(DI)
SaveDao.class
public interface SaveDao { public void save(); }
SaveDaoImpl.class
public class SaveDaoImpl implements SaveDao { public void save(){ System.out.println("保存完毕"); } }
Service.class
public interface Service { public void save(); }
ServiceImpl.class
public class ServiceImpl implements Service { //传统方法 //private SaveDao saveDao = new SaveDaoImpl(); private SaveDao saveDao; public void setSaveDao(SaveDao saveDao) { //解耦,通过spring动态注入一个dao(此处就体现了接口的强大作用) this.saveDao = saveDao; } public void save(){ this.saveDao.save(); } }
spring-context.xml(放在resources资源目录)
<?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: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/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="saveService" class="com.test.ServiceImpl"> <property name="saveDao" ref="saveDao" /> <!--name是setter方法名(去掉"set",首字母变小写),ref指另外的一个bean--> </bean> <bean id="saveDao" class="com.test.SaveDaoImpl" /> </beans>
测试
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-context.xml"); Service service = ((ServiceImpl) applicationContext.getBean("saveService")); service.save(); } }
笔记
IOC
控制反转:IOC是一种概念,把程序中的类与类的依赖关系交给外部容器处理,创建对象实例的控制权交给了IOC容器,侧重于原理。(IOC并不是spring独有的,)
依赖注入:Spring控制反转是由DI实现的,创建对象实例时,为这个对象注入属性值或其它对象实例,侧重于实现。
首先我们需要了解为什么需要控制反转,在了解控制发展之前,我们可以了解一下依赖倒置原则。所谓的依赖倒置原则就是将把原本的高层建筑依赖底层建筑“倒置”过来,变成底层建筑依赖高层建筑。这样但我们反复的修改底层建筑的时候就不需要将高层建筑进行修改了。方便代码的维护。个人理解:控制反转的目的就是便于代码的维护,设计思路就是利用了依赖倒置原则,控制反转的实现方式就是依赖注入。所谓的依赖注入就是将底层的类作为参数传递到上层类中。实现了上层类对下层类的控制。
假如有三个参与者,一个是对象A,一个是IOC容器,一个是对象A的外部资源
依赖:对象A依赖IOC容器,需要IOC容器给对象A提供外部资源
注入:IOC容器注入对象A,给对象A注入了外部资源
控制:IOC容器来控制对象
反转:应用程序需要IOC容器实例化外部资源注入到某一个对象A中,这种行为称为反转
依赖注入:从应用程序的角度来描述,应用程序依赖IOC容器创建并注入它所需要的外部资源(所以整个项目不在需要new,一旦new,依赖注入就体现不了作用了)
控制反转:从IOC容器角度描述,IOC容器控制应用程序,有容器向应用程序注入应用程序需要的外部资源
Spring IOC
IOC容器就是具有依赖注入功能的容器,是可以创建对象的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖;
通过spring容器来解决类与类的依赖关系,达到低耦合效果。
Spring 提供了许多 IOC 容器的实现。比如 XmlBeanFactory,ClasspathXmlApplicationContext等。其中 XmlBeanFactory 就 是针对最基本的IOC 容器的实现,这个 IOC 容器可以读取XML 文件定义的 BeanDefinition(XML 文件中对 bean 的描述)。ApplicationContext 是 Spring 提供的一个高级的 IOC 容器
Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。
AOP面向切面编程
首先举一个简单的例子。比如我们需求,只要对数据库进行的查询,就需要日志记录。那么按照传统的OOP编程的话。就是在每一个查询的服务中添加日志记录的代码。如果每一个查询都写这段重复的代码的话,就违反了面向对象设计原则。而且后期对这段日志代码的维护很困难,而AOP面向切面就针对这段业务逻辑,将他提取出来。目的就获得了逻辑部分各个功能之间的低耦合。就像例子中,查询数据库的业务逻辑,专门写查询数据库的代码。日志记录逻辑。抽取出来。专门写日志记录的代码。
AOP用途:传统的OOP开发的代码逻辑是自上而下,而这自上而下的过程中可能会产生横切性的问题,比如事务管理,日志等,这些是与主逻辑代码关联不是特别大,如果将这些代码放到主逻辑中,会时代吗臃肿和冗余,不利于维护,AOP编程就可以将这些横切性的问题和主业务之间进行分离,从而启动解耦的目的。
AOP本质:对方法前后进行拦截,将所需要的功能编织到拦截的方法中
spring IOC本身就是个大的工厂bean,用来生成我们所需要的bean,但是bean和bean之间难免会产出依赖,解决这个问题的办法就是通过DI这个技术,降低类和类之间的耦合度的问题