Spring总结:
引出Spring:解耦的思想:
问题:若把IEmployeeDAO的实现修改为:EmployeeDAOHibernateImpl,需要修改Java代码
----->简单工厂设计模式
----->把创建对象的职责交给工厂来管理.
小结:这样在更换持久层的技术,不会去修改源代码
IoC Di aop
发现问题:
在service中要去处理事物相关的一些繁杂的操作:
---->找一个中介来去处理,service中只是执行和业务相关的操作
Spring能帮我们做什么:
①.Spring能帮我们根据配置文件创建及组装对象之间的依赖关系。
②.Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制。
③.Spring能非常简单的帮我们管理数据库事务。
④.Spring还提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,而且自己也提供了一套JDBC访问模板来方便数据库访问。
⑤.Spring还提供与第三方Web(如Struts1/2、JSF)框架无缝集成,而且自己也提供了一套Spring MVC框架,来方便web层搭建。
⑥.Spring能方便的与Java EE(如Java Mail、任务调度)整合,与更多技术整合(比如缓存框架)。
Spring 的概述:
1. Spring是一个轻量级的DI/IoC和AOP容器的开源框架,来源于Rod Johnson 在其著作《Expert one on one J2EE design and development》中阐述的部分理念和原型衍生而来。
2. 提倡”最少入侵” 的方式,意味着我们可以随时去安装和卸载spring
Spring常用的术语
1. 应用程序:是能完成我们所需要功能的成品,比如购物网站、OA系统。
2. 框架:是能完成一定功能的半成品,比如我们可以使用框架进行购物网站开发;框架做一部分功能,我们自己做一部分功能,这样应用程序就创建出来了。而且框架规定了你在开发应用程序时的整体架构,提供了一些基础功能,还规定了类和对象的如何创建、如何协作等,从而简化我们开发,让我们专注于业务逻辑开发。
3. 非侵入式设计:从框架角度可以这样理解,无需继承框架提供的类,这种设计就可以看作是非侵入式设计,如果继承了这些框架类,就是侵入设计,如果以后想更换框架之前写过的代码几乎无法重用,如果非侵入式设计则之前写过的代码仍然可以继续使用。
4. 轻量级及重量级:轻量级是相对于重量级而言的,轻量级一般就是非入侵性的、所依赖的东西非常少、资源占用非常少、部署简单等等,其实就是比较容易使用,而重量级正好相反。
5. POJO:POJO(Plain Old Java Objects)简单的Java对象,它可以包含业务逻辑或持久化逻辑,但不担当任何特殊角色且不继承或不实现任何其它Java框架的类或接口。
6. 容器(Container):在日常生活中容器就是一种盛放东西的器具,从程序设计角度看就是装对象的的对象,因为存在放入、拿出等操作,所以容器还要管理对象的生命周期。
优势:
1. 低耦合/低侵入(降低组建之间的耦合度,实现软件各层之间的解耦)
2. 声明事物管理器
3. 方便集成其他框架的开发
4. 降低javaEE的开发难度
5. Spring框架中包括JavaEE 三层的每一层的解决方案(一站式)
Spring产品及其框架结构:
Spring Data
用于简化数据库访问,并支持云服务的开源框架。旨在统一和简化对各类型持久化存储, 而不拘泥是关系型数据库还是NoSQL数据存储。
Spring Batch
专门针对企业级系统中的日常批处理任务的轻量级框架,能够帮助开发者方便地开发出强壮、高效的批处理应用程序。
Spring Integration
为Spring编程模型提供了一个支持企业集成模式(Enterprise Integration Patterns)的扩展,在应用程序中提供轻量级的消息机制,可以通过声明式的适配器与外部系统进行集成。
Spring Security(安全框架,比shrio框架复杂一点)
早期称为Acegi,基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架;。
Spring Roo,快速应用程序开发工具,可以在短时间内方便地构建应用程序。
Spring Mobile,对Spring MVC的扩展,旨在简化移动Web应用的开发。
Spring for Android,用于简化Android原生应用程序开发的Spring扩展。
等等
如下图所示:了解即可,清楚自己学什么
Spring框架架构:
Core Container(核心容器)包含有Beans、Core、Context和SpEL模块。
Data Access/Integration层包含有JDBC、ORM、OXM、JMS和Transaction模块。
Web层包含了Web、Web-Servlet、WebSocket、Web-Porlet模块。
AOP模块提供了一个符合AOP联盟标准的面向切面编程的实现。
Test模块支持使用JUnit和TestNG对Spring组件进行测试。
Spring框架版本:
Spring2.5:
¨ 拥抱驱动编程。
支持SimpleJdbcTemplate的命名参数操作。
Spring3.x:
不再支持JDK1.4;
¨全面支持泛型。
支持SpEL.
支持WebService的OXM。
Spring4.x:
支持Java8,支持JavaEE6规范。
泛型限定式依赖注入。
对Hibernate4的集成和事务提供更好的管理方案。
Spring框架包分析:
现在都提倡使用Maven去下载Spring的jar:
下载地址:(直接输入)
http://repo.spring.io/libs-release-local/org/springframework/spring/
spring-framework-4.x.RELEASE:Spring核心组件。
docs: Spring开发、帮助文档。
libs: Spring核心组件的。jar包、源代码、文档。
schema: Spring配置文件的schema约束文件。
spring-framework-3.x.RELEASE-dependencies:Spring依赖的第三方组件。
包含了各大开源组织提供的依赖jar。比如apache common下的:dbcp.jar pool.jar logging.jar
Maven:
IoC:Inverse of Control(控制反转):
Spring的容器对象:BeanFactory和ApplicationContext对象.
BeanFactory:是Spring中最底层的接口,只提供了最简单的IoC功能,负责配置,创建和管理bean。
在实际开发中,一般不使用BeanFactory,而推荐使用ApplicationContext(应用上下文),原因如下。
BeanFactory和ApplicationContext的区别
1、ApplicationContext继承了BeanFactory,拥有了基本的IoC功能;
2、除此之外,ApplicationContext还提供了以下的功能:
①、支持国际化;
②、支持消息机制;
③、支持统一的资源加载;
④、支持AOP功能;
ApplicationContext常见实现类:ClassPathXmlApplicationContext:读取classpath中的资源.
bean的创建时机:
1.ApplicationContext在加载的时候就会创建所有的bean(Web应用建议),在启动Tomcat时,创建好所有的bean对象.
2.BeanFactory需要等到拿bean的时候才会创建bean(桌面程序)
优化性能
延迟实例化的配置:
针对于当前xml中所有的bean。
<beans default-lazy-init="default | false | true">
针对于指定的bean:
<bean lazy-init="default | false | true">
方式一:
使用xml的形式:
<bean标签的继承>
<bean id=”parent” abstract=”true” >
<property name=”” value=”” ></property>(基本类型)
<property name=”” ref=”” ></property>(引用类型)
</bean>
<bean id=”” class=”” init-method=”” destory-method=”” scope=”” parent=”” ></bean>
1. <bean>的id/name:
在Spring配置中,id和name属性都可以定义bean元素的名称,不同的是:
lid属性,遵守XML语法ID约束。从Spring3.1开始,id属性不再是ID类型了,而是String类型,也就是说id属性也可以使用“/”开头了,而bean元素的id的唯一性由容器负责检查。
lname属性,就可以使用很多特殊字符,比如在Spring和Struts1或Spring MVC的整合中,就得使用name属性来的定义bean的名称。当然也可以使用name属性为<bean/>元素起多个别名,多个别名之间使用逗号或空格隔开,在代码中依然使用BeanFactory对象.getBean(...)方法获取。
注意:通俗的理解:
Id表示的是唯一的标识(运行原理结合下的di),class表示的是类的权限类名:把哪个类交给spring去管理,帮助我们去创建,只需要在ApplicationContext容器中使用getBean(“id”,.class)方法就可以获得对象
2. <bean>元素的抽取
创建一个<bean> 定义为abstrcat(抽象)不必要去实现这个类(不用去写class),把多个bean对象中相同类型的属性提取出来,(化繁为简),子<bean>标签只需要定义一个parent属性给其一个id,xml的代码抽取
标签具有的属性:
1. scope=””(理解:要把action设置为多例的模式,单例存在的问题:线程不安全的问题,多线程并发访问同一资源对象,产生线程的阻塞,堵死等现象)
前台使用的技术是springmvc--> controller为单例
........使用................struts2--------> action为多例 ,在使用xml配置的时候一定要配置生命周期
在开发中主要使用 scope="singleton"、 scope="prototype"
对于Struts2中的Action使用prototype类型,其他使用singleton
(图看不懂了打电话)
2. 初始化和销毁的方法:
简而言之:在把对象交给spring的时候,在调用构造器之后想要初始化,在容器销毁之前,要执行销毁的操作,在其对应的类中去创建对应的方法
重点:在xml当中的配置:
init-method:bean生命周期初始化方法,对象创建后就进行调用
destroy-method:容器被销毁的时候,如果bean被容器管理,会调用该方法。
scope="prototype",那么容器只负责创建和初始化,它并不会被spring容器管理
方式二:
使用注解的方式:
推理思想:xml中有的方式,方法,那么在注解当中也一定会存在,使用标签来完成IoC,就必须有IoC标签的解析器 :context:component-scan(IoC扫描器)
1. .bean组件版型标签(规范!!!!!!!!)
@Service用于标注业务层组件、
@Controller用于标注控制层组件(如struts中的action)、
@Repository用于标注数据访问组件,即DAO组件。
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
理解:相当于<bean>中的class (“”)-->id]
2. @Scope("prototype")
***这两个注解在方法上贴
3. @PostConstruct (在构造器之后执行的方法:表示的是初始化的方法)
4. @PreDestroy(表示在容器销毁之前执行的方法,表示的是销毁的方法)
选用xml还是注解:
1),Annotation(注解):使用方便,XML文件很小,但是,依赖关系又重新回到了代码当中;
2),XML:使用稍微复杂,但是,代码很干净,代码不会很任何框架产生关系;XML安全;
了解:
使用@Component的限制:
1),不能运用到静态工厂方法和实例工厂方法,但是可以使用到FactoryBean;
2),对于没有源代码的类(框架内部的预定义类),只能用XML配置;必然DataSource就只能使用XML方式来做IOC.
注意事项,以及拓展:
底层是如何去创建这个类的?
使用了工厂去创建,框架的底层通过反射去创建对象
DI:Dependency Injection(依赖注入)
简而言之:在Spring创建对象的时候,把值去注入到属性当中去
注入方式:
1):手动装配(XML方式),必须掌握.
2):自动装配(注解方式),必须掌握.
自动装配(XML方式),了解.
(1) :手动装配(XML方式) 必须通过对应的set方法
简单数据类型,使用的是value
符合数据类型,使用的是ref(理解,自定义的类,或者交给容器管理的其他类)
集合数据类型:使用集合元素
Value:
<property name=”” value=””/>
Ref:
<property name=”” ref=””/>
List
<property name=”” >
<set> <value>值</value> </set>
<list> <value>值</value> </list>
<array> <value>值</value> </array>
<map>
<entry key = “” value=””>
</map>
</property >
(2) 注解的方式:
使用Spring框架自身提供的标签:Autowired
---------------------------------------------------------
Autowired和Qualifier标签:
1. 通过@Autowired标签可以让Spring自动的把属性需要的对象从Spring容器中找出来,并注入(设置)给该属性。
2. <context:annotation-config /> 开启di扫描器
3. @Autowired标签贴在字段或者setter方法上。
4. @Autowired可以同时为一个属性注入多个对象。
public void setXxx(OtherBean1 other1,OtherBean2 other2) {}
5. 使用@Autowired标签可以注入Spring内置的重要对象,比如BeanFactory,ApplicationContext。
6. 默认情况下@Autowired标签必须要能找到对应的对象,否则报错。不过,可使用required=false来避免该问题:@Autowired(required=false)
@Autowired找bean的方式:
1)、首先按照依赖对象的类型找(也就是class),如果找到则使用setter方法或者字段直接注入;
2)、如果在Spring上下文中找到多个匹配的类型,再按照名字(name)去找,如果没有匹配则报错;
3)、可以通过使用@Qualifier("otherBean")标签来规定依赖对象按照bean的id+类型去找;
使用JavaEE规范提供的标签:Resource
---------------------------------------------------------
@Resource标签:
(1) @Resource标签是JavaEE规范的标签;
(2) @Resource标签也可以作用于字段或者setter方法;
(3) 也可以使用@Resource标签注入一些spring内置的重要对象,比如BeanFactory.ApplicationContext;
(4) @Resource必须要求有匹配的对象;
(5) <context:annotation-config>既引入了@Autowired标签的解析器,也引入了@Resource的解析器;
@Resource标签找bean的方式:
1)、首先按照名字去找,如果找到,就使用setter或者字段注入;
2)、如果按照名字找不到,再按照类型去找,但如果找到多个匹配类型,报错;
3)、可以直接使用name属性指定bean的名称;但是,如果指定的name,就只能按照name去找,如果找不到,就不会再按照类型去找;
动态代理和静态代理
静态代理:在程序运行前就已经存在代理类的字节码文件,代理对象和真实对象的关系在运行前就确定了。
动态代理:动态代理类是在程序运行期间由JVM通过反射等机制动态的生成的,所以不存在代理类的字节码文件。代理对象和真实对象的关系是在程序运行事情才确定的。
静态代理优缺点:
优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。
缺点:
n1.代理对象的某个接口只服务于某一种类型的对象,也就是说每一个真实对象都得创建一个代理对象。
n2.如果需要代理的方法很多,则要为每一种方法都进行代理处理。
n3.如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
核心:1.JDK的动态代理
2.CGLIBE的动态代理
JDK:思想:在使用动态代理的时候就不需要去手动的创建代理的对象,而是交给底层去创建代理对象..通过字节码的方式去JVM去创建代理对象,那么问题随之而来,jvm创建的代理对象是不知道我们要对什么类进行什么操作,在什么时候..需要去定义处理器,代理对象去调用处理器,就能够实现功能模块的处理
------------>:处理器:其实就是事物的处理,以及真实业务的操作
jdk动态代理操作步骤
① 实现InvocationHandler接口,创建自己增强代码的处理器。
② 给Proxy类提供ClassLoader对象和代理接口类型数组,创建动态代理对象。
③ 在处理器中实现增强操作。
---------------------------------
JDK动态代理总结:
1,JAVA动态代理是使用java.lang.reflect包中的Proxy类与InvocationHandler接口这两个来完成的。
2,要使用JDK动态代理,必须要定义接口。
3,JDK动态代理将会拦截所有pubic的方法(因为只能调用接口中定义的方法),这样即使在接口中增加了新的方法,不用修改代码也会被拦截。
4,如果只想拦截一部分方法,可以在invoke方法中对要执行的方法名进行判断。
JDK动态代理API分析:
1、java.lang.reflect.Proxy 类:
Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
主要方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler hanlder)
方法职责:为指定类加载器、一组接口及调用处理器生成动态代理类实例
参数:
loader :类加载器
interfaces :模拟的接口
hanlder :代理执行处理器
返回:动态生成的代理对象
2、java.lang.reflect.InvocationHandler接口:
public Object invoke(Object proxy, Method method, Object[] args)
方法职责:负责集中处理动态代理类上的所有方法调用
参数:
proxy :生成的代理对象
method :当前调用的真实方法对象
args :当前调用方法的实参
CGLIBE:
针对于没有接口的类,如何做代理:cglib和javassist都是针对没有接口,做动态代理的.
原理: 对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
CGLIB代理总结:
1,CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。
2,要求类不能是final的,要拦截的方法要是非final、非static、非private的。
3,动态代理的最小单位是类(所有类中的方法都会被处理);
在Spring中:
n若目标对象实现了若干接口,Spring就会使用JDK动态代理。
n若目标对象没有实现任何接口,Spring就使用CGLIB库生成目标对象的子类。
对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统,也更符合面向接口编程规范。
AOP:Aspect oritention programming(面向切面编程)
Aop的优势:
降低代码的耦合度
体现责任分离,使service更专注与业务逻辑的处理,而不是去处理与其无关事件
AOP的目的:
AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,
便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
AOP的优势:
降低模块的耦合度、使系统容易扩展、更好的代码复用性
说人话: 把多个方法前/后的共同代码抽离出来,使用动态代理机制来控制,先执行抽离出来的代码,再执行每一个真实方法.
Spring的AOP使用动态代理实现:
如果一个类实现了接口,那么spring就使用JDK的动态代理完成AOP;
如果一个类没有实现接口,那么spring就是用cglib完成AOP;
AOP当中的概念:
1、切入点(Pointcut):在哪些类,哪些方法上切入(where);
2、增强(Advice):早期翻译为通知,在方法执行的什么时机(when:方法前/方法后/方法前后)做什么(what:增强的功能);
3、切面(Aspect):切面=切入点+通知,通俗点就是:什么时机,什么地点,做什么!
4、织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)。
Aop的应用:事务;日志
AspectJ切入点语法如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?
name-pattern(param-pattern)throws-pattern?)
翻译如下:
execution(<访问修饰符>? <返回类型> <声明类型>? <方法名>(<参数>) <异常>?)
Spring中的各种增强
各种不同的增强:
aop:before(前置增强):在方法执行之前执行增强;
aop:after-returning(后置增强):在方法正常执行完成之后执行增强;
aop:after-throwing(异常增强):在方法抛出异常退出时执行增强;
aop:after(最终增强):在方法执行之后执行,相当于在finally里面执行;可以通过配置throwing来获得拦截到的异常信息
aop:around(环绕增强):最强大的一种增强类型。 环绕增强可以在方法调用前后完成自定义的行为,环绕通知有两个要求,
1.方法必须要返回一个Object(返回的结果)
2.方法的第一个参数必须是ProceedingJoinPoint(可以继续向下传递的切入点)
(这个也就是when:如何去增强)
方式一
方式二:(使用一个自定义的事物管理器举例说明)
Spring对事物的支持
Spring的事务管理主要包括3个接口:
TransactionDefinition:封装事务的隔离级别,超时时间,是否为只读事务和事务的隔离级别和传播规则等事务属性,可通过XML配置具体信息。
PlatformTransactionManager:根据TransactionDefinition提供的事务属性配置信息,创建事务。
TransactionStatus:封装了事务的具体运行状态。比如,是否是新开启事务,是否已经提交事务,设置当前事务为rollback-only等。
Spring支持编程式事务管理和声明式事务管理。
--------------------------------------------------------------------------------
l编程式事务管理:事务和业务代码耦合度太高。
l声明式事务管理:侵入性小,把事务从业务代码中抽离出来,提供维护性。
Spring的事务管理:
1. PlatformTransactionManager:接口统一抽象处理事务操作相关的方法;
1):TransactionStatus getTransaction(TransactionDefinition definition):
根据事务定义信息从事务环境中返回一个已存在的事务,或者创建一个新的事务,并用TransactionStatus描述该事务的状态。
ü 2):void commit(TransactionStatus status):
根据事务的状态提交事务,如果事务状态已经标识为rollback-only,该方法执行回滚事务的操作。
ü 3):void rollback(TransactionStatus status):
将事务回滚,当commit方法抛出异常时,rollback会被隐式调用
2. 在使用spring管理事务的时候,首先得告诉spring使用哪一个事务管理器; 看图
3,常用的事务管理器:
DataSourceTransactionManager:使用JDBC,MyBatis的事务管理器;
HibernateTransactionManager:使用Hibernate的事务管理器;
基于xml的配置
注解的方式
@Transactional
但是要开启注解扫描器
思考 Mapper