1、IoC(Inversion of Control) java
(1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控。控制权由应用代码中转到了外部容器,控制权的转移是所谓反转。 对于Spring而言,就是由Spring来控制对象的生命周期和对象之间的关系;IoC还有另一个名字——“依赖注入(Dependency Injection)”。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某种依赖关系注入到组件之中。 web
(2). 在Spring的工做方式中,全部的类都会在spring容器中登记,告诉spring这是个什么东西,你须要什么东西,而后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其余须要你的东西。全部的类的建立、销毁都由 spring来控制,也就是说控制对象生存周期的再也不是引用它的对象,而是spring。对于某个具体的对象而言,之前是它控制其余对象,如今是全部对象都被spring控制,因此这叫控制反转。正则表达式
(3). 在系统运行中,动态的向某个对象提供它所须要的其余对象。 spring
(4). 依赖注入的思想是经过反射机制实现的,在实例化一个类时,它经过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中。 总而言之,在传统的对象建立方式中,一般由调用者来建立被调用者的实例,而在Spring中建立被调用者的工做由Spring来完成,而后注入调用者,即所谓的依赖注入or控制反转。 注入方式有两种:依赖注入和设置注入; IoC的优势:下降了组件之间的耦合,下降了业务对象之间替换的复杂性,使之可以灵活的管理对象。express
2、AOP(Aspect Oriented Programming)编程
(1). AOP面向方面编程基于IoC,是对OOP的有益补充;数组
(2). AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了 多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的 逻辑或责任封装起来,好比日志记录,便于减小系统的重复代码,下降模块间的耦合度,并有利于将来的可操做性和可维护性。缓存
(3). AOP表明的是一个横向的关 系,将“对象”比做一个空心的圆柱体,其中封装的是对象的属性和行为;则面向方面编程的方法,就是将这个圆柱体以切面形式剖开,选择性的提供业务逻辑。而 剖开的切面,也就是所谓的“方面”了。而后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹,但完成了效果。安全
(4). 实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法建立“方面”,从而使得编译器能够在编译期间织入有关“方面”的代码。性能优化
(5). Spring实现AOP:JDK动态代理和CGLIB代理 JDK动态代理:其代理对象必须是某个接口的实现,它是经过在运行期间建立一个接口的实现类来完成对目标对象的代理;其核心的两个类是InvocationHandler和Proxy。 CGLIB代理:实现原理相似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操做字节码实现的,性能比JDK强;须要引入包asm.jar和cglib.jar。 使用AspectJ注入式切面和@AspectJ注解驱动的切面实际上底层也是经过动态代理实现的。
(6). AOP使用场景:
Authentication 权限检查
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 延迟加载
Debugging 调试
logging, tracing, profiling and monitoring 日志记录,跟踪,优化,校准
Performance optimization 性能优化,效率检查
Persistence 持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务管理
另外Filter的实现和struts2的拦截器的实现都是AOP思想的体现。
3、详细介绍
Spring提供了不少轻量级应用开发实践的工具集合,这些工具集以接口、抽象类、或工具类的形式存在于Spring中。经过使用这些工具集,能够实现应用程序与各类开源技术及框架间的友好整合。好比有关jdbc封装的数据访问工具Spring JDBC,有关编写单元测试的spring test包以及spring-mock,有关访问动态脚本语言的Spring Script,另外还有发送邮件的工具Spring Mail、日程及任务处理工具Spring scheduling等。 能够这么说,大多数企业级应用开发中常常涉及到的一些通用的问题,均可以经过Spring提供的一些实用工具包轻松解决。
依赖注入的三种方式:(1)接口注入(2)Construct注入(3)Setter注入
控制反转(IoC)与依赖注入(DI)是同一个概念,引入IOC的目的:(1)脱开、下降类之间的耦合;(2)倡导面向接口编程、实施依赖倒换原则; (3)提升系统可插入、可测试、可修改等特性。
具体作法:
(1)将bean之间的依赖关系尽量地抓换为关联关系;
(2)将对具体类的关联尽量地转换为对Java interface的关联,而不是与具体的服务对象相关联;
(3)Bean实例具体关联相关Java interface的哪一个实现类的实例,在配置信息的元数据中描述;
(4)由IoC组件(或称容器)根据配置信息,实例化具体bean类、将bean之间的依赖关系注入进来。
org.springframework.beans及org.springframework.context包是Spring IoC容器的基础。BeanFactory提供的高级配置机制,使得管理任何性质的对象成为可能。ApplicationContext是BeanFactory的扩展,功能获得了进一步加强,好比更易与Spring AOP集成、消息资源处理(国际化处理)、事件传递及各类不一样应用层的context实现(如针对web应用的WebApplicationContext)。 简而言之,BeanFactory提供了配制框架及基本功能,而ApplicationContext则增长了更多支持企业核心内容的功能。ApplicationContext彻底由BeanFactory扩展而来,于是BeanFactory所具有的能力和行为也适用于ApplicationContext。
IoC容器负责容纳bean,并对bean进行管理。在Spring中,BeanFactory是IoC容器的核心接口。它的职责包括:实例化、定位、配置应用程序中的对象及创建这些对象间的依赖。Spring为咱们提供了许多易用的BeanFactory实现,XmlBeanFactory就是最经常使用的一个。该实现将以XML方式描述组成应用的对象以及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个彻底可配置的系统或应用。
实现化容器:
将XML配置文件分拆成多个部分是很是有用的。为了加载多个XML文件生成一个ApplicationContext实例,能够将文件路径做为字符串数组传给ApplicationContext构造器。而bean factory将经过调用bean defintion reader从多个文件中读取bean定义。
一般状况下,Spring团队倾向于上述作法,由于这样各个配置并不会查觉到它们与其余配置文件的组合。另一种方法是使用一个或多个的<import/>元素来从另一个或多个文件加载bean定义。全部的<import/>元素必须放在<bean/>元素以前以完成bean定义的导入。 让咱们看个例子:
<beans><import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> </beans>
在上面的例子中,咱们从3个外部文件:services.xml、messageSource.xml及themeSource.xml来加载bean定义。这里采用的都是相对路径,所以,此例中的services.xml必定要与导入文件放在同一目录或类路径,而messageSource.xml和themeSource.xml的文件位置必须放在导入文件所在目录下的resources目录中。正如你所看到的那样,开头的斜杠‘/’实际上可忽略。所以不用斜杠‘/’可能会更好一点。
根据Spring XML配置文件的Schema(或DTD),被导入文件必须是彻底有效的XML bean定义文件,且根节点必须为<beans/> 元素。
BeanFactory和FactoryBean的区别,简而言之,BeanFactory是加载的容器,加载一切的BEAN,而FactoryBean用于建立代理类
===============================================================上面已讲到
BeanFactory它的职责包括:实例化、定位、配置应用程序中的对象及创建这些对象间的依赖。
FactoryBean(一般状况下,bean无须本身实现工厂模式,Spring容器担任工厂角色;但少数状况下,容器中的bean自己就是工厂,其做用是产生其它bean实例),做用是产生其余bean实例。一般状况下,这种bean没有什么特别的要求,仅须要提供一个工厂方法,该方法用来返回其余bean实例。由工厂bean产生的其余bean实例,再也不由Spring容器产生,所以与普通bean的配置不一样,再也不须要提供class元素。
ProxyFactoryBean用于建立代理(根据Advisor生成的Bean,也就是TargetBean的代理)
咱们的Advisor,PointCut等等,其最终目的都是为了建立这个代理。
===============================================================下面将讲到
AOP全名Aspect-Oriented Programming,中文直译为面向切面(方面)编程,当前已经成为一种比较成熟的编程思想,能够用来很好的解决应用系统中分布于各个模块的交叉关注点问题。在轻量级的J2EE中应用开发中,使用AOP来灵活处理一些具备横切性质的系统级服务,如事务处理、安全检查、缓存、对象池管理等,已经成为一种很是适用的解决方案。 AOP中比较重要的概念有:Aspect、JoinPoint、PonitCut、Advice、Introduction、Weave、Target Object、Proxy Object等
引介(Introduction)是指给一个现有类添加方法或字段属性,引介还能够在不改变现有类代码的状况下,让现有的Java类实现新的接口,或者为其指定一个父类从而实现多重继承。相对于加强(Advice)能够动态改变程序的功能或流程来讲,引介(Introduction)则用来改变一个类的静态结构。好比咱们可让一个现有为实现java.lang.Cloneable接口,从而能够经过clone()方法复制这个类的实例。
拦截器是用来实现对链接点进行拦截,从而在链接点前或后加入自定义的切面模块功能。在大多数JAVA的AOP框架实现中,都是使用拦截器来实现字段访问及方法调用的拦截(interception)。所用做用于同一个链接点的多个拦截器组成一个链接器链(interceptor chain),连接上的每一个拦截器一般会调用下一个拦截器。Spring AOP及JBoos AOP实现都是采用拦截器来实现的。
面向对象编程(OOP)解决问题的重点在于对具体领域模型的抽象,而面向切面编程(AOP)解决问题的关键则在于对关注点的抽象。也就是说,系统中对于一些须要分散在多个不相关的模块中解决的共同问题,则交由AOP来解决;AOP可以使用一种更好的方式来解决OOP不能很好解决的横切关注点问题以及相关的设计难题来实现松散耦合。所以,面向方面编程 (AOP) 提供另一种关于程序结构的思惟完善了OOP,是OOP的一种扩展技术,弥补补了OOP的不足。
AOP概念详解:注意如下实例<aop:开头的AspectJ的概念,Spring没有分的这么细。
— 方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现, 而后能够经过@Aspect标注或在applictionContext.xml中进行配置:
<aop:aspect id="fourAdviceAspect" ref="fourAdviceBean" order="2">
— 链接点(Joinpoint):程序执行过程当中的行为,如方法的调用或特定的异常被抛出,在代码上有JoinPoint类和ProceedingJoinPoint类,以下所示,能够经过JoinPoint获取不少参数,JoinPoint通常用在Advice实现方法中做为参数传入,ProceedingJoinPoint用于实现围绕Advice的参数传入。 经过下面JoinPoint的接口能够看出经过JoinPoint能够获得代理对象和Target对象。
— 切入点(Pointcut):指定一个Adivce将被引起的一系列链接点的集合。AOP框架必须容许开发者指定切入点,例如,使用正则表达式。
xml中配置:
<aop:pointcut id="myPointcut" expression="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" />
或使用Annoation :@pointcut("execution * transfer(..)")并用一个返回值为void,方法体为空的方法来命名切入点如: private void anyOldTransfer(){}
以后就能够在Advice中引用,如: @AfterReturning(pointcut="anyOldTransfer()", returning="reVal")
关于PointCut中使用的execution的说明:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
modifiers-pattern:方法的操做权限
ret-type-pattern:返回值
declaring-type-pattern:方法所在的包
name-pattern:方法名
parm-pattern:参数名
throws-pattern:异常
记忆法则就是Java定义一个方法时的样子:public boolean produceValue(int oo) throws Exception, 只要在方法名前加上包名就能够了。
其中,除ret-type-pattern和name-pattern以外,其余都是可选的。上例中,execution(* com.spring.service.*.*(..))表示com.spring.service包下,返回值为任意类型;方法名任意;参数不做限制的全部方法。
常见的PointCut结构图:
— 通知(Advice):在特定的链接点,AOP框架执行的动做。各类类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器作通知模型,维护一个“围绕”链接点的拦截器链。Advice中必须用到PointCut
在xml中配置,配置中的method为Aspect实现类中的方法名,使用pointcut自定义或pointcut-ref进行引用已有pointcut
<aop:before pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="authority" />
<aop:after pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" />
<aop:after-returning pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="log" />
<aop:around pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="processTx" />
<aop:after-throwing pointcut-ref="myPointcut" method="doRecovertyActions" throwing="ex" />
或使用Annoation:
@Before("execution(* com.wicresoft.app.service.impl.*.*(..))")
@AfterReturning(returning="rvt", pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))")
@AfterThrowing(throwing="ex", pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))")
@After("execution(* com.wicresoft.app.service.impl.*.*(..))")
@Around("execution(* com.wicresoft.app.service.impl.*.*(..))")
注意
使用方法拦截器的around通知,需实现接口MethodInterceptor:
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
invoke()方法的MethodInvocation 参数暴露将被调用的方法、目标链接点、AOP代理和传递给被调用方法的参数。 invoke()方法应该返回调用的结果:链接点的返回值。
一个简单的MethodInterceptor实现看起来以下:
注意MethodInvocation的proceed()方法的调用。这个调用会应用到目标链接点的拦截器链中的每个拦截器。大部分拦截器会调用这个方法,并返回它的返回值。可是, 一个MethodInterceptor,和任何around通知同样,能够返回不一样的值或者抛出一个异常,而不调用proceed方法。可是,没有好的缘由你要这么作。
Before通知:需实现MethodBeforeAdvice接口
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method m, Object[] args, Object target) throws Throwable;
}
Throw通知,需实现ThrowsAdvice接口
After Returning通知须直线AfterReturningAdvice接口
public interface AfterReturningAdvice extends Advice {
void afterReturning(Object returnValue, Method m, Object[] args, Object target)
throws Throwable;
}
— 引入(Introduction):添加方法或字段到被通知的类,引入新的接口到任何被通知的对象。例如,你可使用一个引入使任何对象实现IsModified接口,来简化缓存。使用introduction要有三个步骤(1)声明新接口(2)建立本身的IntrouductionInterceptor经过Implements IntroductionInterceptor或extends DelegatingIntroductionInterceptor 并同时implements(1)中声明的接口 (3)将新接口和自定义的IntroductionInterceptor配置到DefaultIntroductionAdvisor中,而后将前三者配置到ProxyFactoryBean中。
— 拦截器(Advisor )经常使用的有PointCutAdvisor和IntroudtionAdvisor。前者Advisor有PointCut和Advice组成,知足Poincut(指定了哪些方法须要加强),则执行相应的Advice(定义了加强的功能),后者由Introduction构成。PointCutAdvisor主要是根据PointCut中制定的Target Objects的方法在调用(前,后,around,throws, after-return等)时引入新的Aspect中的methods, 而IntroductionAdvisor主要是引入新的接口到Targets对象中。
一、 PointcutAdvisor: Advice和Pointcut,默认实现为DefaultPointcutAdvisor, 还有NameMatchMethodPointcutAdvisor,RegexpMethodPointcutAdvisor等。
其中NameMacthMethodPointCutAdvisor、RegexpMethodPointCutAdvisor 能够对比经常使用的PointCut类有NameMatchedMethodPointCut和JdkRegexMethodPointCut。
前者须要注入mappedName和advice属性,后者须要注入pattern和advice属性。其中mappedName和pattern是直接配置的值,而advice须要本身实现具体的advice,可见实现advisor的时候,不须要实现PointCut,通常PointCut只须要配置就行了,不须要具体实现类
mappedName指明了要拦截的方法名,pattern按照正则表达式的方法指明了要拦截的方法名,advice定义了一个加强(须要本身实 现MethodBeforeAdvice、 MethodAfterAdvice、ThrowsAdvice、MethodInterceptor接口之 一)。而后在ProxyFactoryBean的拦截器(interceptorNames)中注入这个PointCutAdvisor便可,如上面这个ProxyFactoryBean是一个静态代理,只能代理一个类给加上AOP,那么这个静态代理须要注入有目标对象,目标对象的接口,和interceptorsNames
二、 IntroductionAdvisor :默认实现为DefaultIntroductionAdvisor,这个主要与Introduction有关,能够参考上面的例子
— 目标对象(Target Object):包含链接点的对象,也被称做被通知或被代理对象。
— AOP代理(AOP Proxy):AOP框架建立的对象,包含通知。在Spring中,AOP代理能够是JDK动态代理或CGLIB代理。如ProxyFactory,ProxyFactoryBean, 下面会进行详细说明
— 编织(Weaving):组装方面来建立一个被通知对象。这能够在编译时完成(例如使用AspectJ编译器),也能够在运行时完成。Spring和其余纯Java AOP框架同样,在运行时完成织入。将Aspect加入到程序代码的过程,对于Spring AOP,由ProxyFactory或者ProxyFactoryBean负责织入动做。
经过ProxyFactory能够将对符合条件的类调用时添加上Aspect。
或者 可以使用XML声明式 ProxyFactoryBean:须要设定 target,interceptorNames(能够是Advice或者Advisor,注意顺序, 对接口代理需设置proxyInterfaces
注意:一个ProxyFactoryBean只能指定一个代理目标,不是很方便,这就产生了自动代理。经过自动代理,能够实现自动为多个目标Bean实现AOP代理、避免客户端直接访问目标Bean(即getBean返回的都是Bean的代理对象)。spring的自动代理是经过BeanPostProcessor实现的,容器载入xml配置后会修改bean为代理Bean,而id不变。
ApplicationContext能够直接检测到定义在容器中的BeanPostProcessor,BeanFactory须要手动添加。
有2种经常使用的BeanPostProcessor:
1.BeanNameAutoProxyCreator 故名思议,BeanName须要注入的两个属性有BeanNames和interceptorNames
2.DefaultAdvisorAutoProxyCreator: DefaultAdvisorAutoProxyCreator和BeanNameAutoProxyCreator不一样的是,前者只和Advisor 匹配, 该类实现了BeanPostProcessor接口。当应用上下文读入全部的Bean的配置信息后,该类将扫描上下文,寻找全部的Advisor,他将这些Advisor应用到全部符合切入点的Bean中。因此下面的xml中没有绑定也无需绑定DefaultAdvisorAutoProxyCreator与Advisor的关系。
在使用Aonnotation的时候,须要进行在ApplicationContext.xml中进行配置:
综上,Spring下AOP的配置与实现,BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator已经部分简化了AOP配置,然而仍是很繁琐: 首先要编写xxxAdvice类(须要本身实现MethodBeforeAdvice、MethodAfterAdvice、 ThrowsAdvice、MethodInterceptor接口之一),而后还要在xml中配置Advisor,还要在Advisor中注入 Advice,最后还要将Advisor加入ProxyFactoryBean、BeanNameAutoProxyCreator或者 DefaultAdvisorAutoProxyCreator中
。
实际上AOP不止Spring进行了实现,还有AspectJ,后者对AOP中的概念实现比较完全,能够看上面,而Spring中对AOP的方方面面进行简化,拿上面定义的regexpFilterPointcutAdvisor是一种Advisor包含了PointCut和Advice,而此处的PointCut就是pattern属性的值了,没有特定的PointCut Bean定义,而advice定义了Bean。而其余概念Aspect, JoinPoint都融汇于Advice的实现中即Advisor(MethodBeforeAdvice等和MethodIntector接口的实现类)或IntroductionInterceptor了。