让对象与对象(模块与模块)之间的关系没有通过代码来关联,都是通过配置类说明管理的
(Spring根据这些配置 内部通过反射去动态的组装对象)
*.Spring是一个容器,凡是在容器里的对象才会有Spring所提供的这些服务和功能。
Spring框架的核心组件是Spring IoC容器(BeanFacory接口或者ApplicationContext接口)和Spring配置文件(或者注解配置信息)。
Spring的基本思想是:把对象之间的依赖关系转移到配置文件(或者注解配置)中,由工厂类(BeanFacory接口)来创建对象。
由容器动态地创建并注入对象,决定所配置对象的创建、管理和销毁。
程序执行过程:
(1)根据业务要求创建实体类或给出接口的实现;
(2)利用所创建的类,在配置文件中配置Bean信息;
(3)创建Spring容器(该容器与配置文件相关联——读取配置信息)
(4)从容器中获取实例对象,由对象调用方法完成所需要的业务处理。
Spring容器和被管理的bean
Spring有两个核心接口:BeanFactory和ApplicationContext,其中ApplicationContext是
BeanFactory的子接口。他们都可以代表Spring容器。
Spring容器是生成Bean实例的工厂,并管理Spring中的bean。包括数据源、Hibernate的SessionFactory、事务管理器。
①Spring最基本的接口就是BeanFactory
BeanFactory有很多实现类,通常使用XmlBeanFactory,推荐使用ApplictionContext,它是
BeanFactory的子接口,
ApplictionContext的实现类为
FileSystemXmlApplicationContext 和ClassPathXmlApplicationContext
FileSystemXmlApplicationContext:基于文件系统的XML配置文件创建ApplicationContext;
ClassPathXmlApplicationContext:基于类加载路径下的xml配置文件创建ApplicationContext。
②ApplicationContext的事件机制
ApplicationContext事件机制是基于观察者设计模式实现的。
通过ApplicationEvent类和ApplicationListener接口,
ApplicationEvent:容器事件,必须由ApplicationContext发布;
ApplicationListener:监听器,可有容器内的任何监听器Bean担任。
③容器中bean的作用域
singleton:单例模式,在整个Spring IoC容器中,singleton作用域的Bean将只生成一个实例。
prototype:每次通过容器的getBean()方法获取prototype作用域的Bean时,都将产生一个新的Bean实例。
request:对于一次HTTP请求,request作用域的Bean将只生成一个实例,这意味着,在同一次HTTP请求内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring时,该作用域才真正有效。
对于一次HTTP会话,session作用域的Bean将只生成一个实例,这意味着,在同一次HTTP会话内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring时,该作用域才真正有效。
global session:每个全局的HTTP Session对应一个Bean实例。在典型的情况下,仅在使用portlet context的时候有效,同样只在Web应用中有效。
注意:request和session作用域只在web应用中才生效,并且必须在web应用中增加额外的
配置才会生效,为了让request,session两个作用域生效,必须将HTTP请求对象绑定到为该请
求提供服务的线程上,这使得具有request和session作用域的Bean实例能够在后面的调用链中被
访问。
当支持Servlet2.4及以上规范的web容器时,我们可以在web应用的web.xml增加如下Listener配
置,该Listener负责为request作用域生效:
class>org.springframework.web.context.request.RequestContextListener class>
如果仅使用了支持Servlet2.4以前规范的web容器,则该容器不支持Listener规范,故无法使用这种配置,可以使用Filter配置方式,我们可以在web应用的web.xml增加如下Filter配置:
<filter>
<filter-name>requestContextFilterfilter-name>
<filter-class>org.springframework.web.filter.RequestContextFilterfilter-class>
filter>
<filter-mapping>
<filter-name>requestContextFilterfilter-name>
/*
filter-mapping>
再如下面的代码:
"p" class="lee.Person" scope="request"/>
这样容器就会为每次HTTP请求生成一个lee.Person的实例当该请求响应结束时,该实例也随之
消失。
如果Web应用直接使用Spring MVC作为MVC框架,即使用SpringDispatchServlet或
DispatchPortlet来拦截所有用户请求,则无需这些额外的配置,因为SpringDispatchServlet或
DispatchPortlet已经处理了所有和请求有关的状态处理。
④获取容器的引用:
通常情况下:
Bean无需访问Spring容器,而是通过Spring容器访问的,即使 需要手动访问Spring容器,程序
也已通过类似下面的代码获取Spring容器 的引用。
ApllicationContext cts = ClassPathApplalicationContext("bean.xml");
但在一些极端的情况下,可能Bean需要访问Spring容器。Spring提供另一种方法访问Spring容
器:
实现BeanFactoryAware接口的Bean,拥有访问Spring容器的能力,实现BeanFactoryAware的
Bean被容器实例化后,会拥有一个引用指向创建他的BeanFactory。BeanFactoryAware只有一
个方法setBeanFactory(BeanFactory beanFactory)该参数指向创建他的BeanFactory。
缺点:污染了代码,使代码与Spring接口耦合在一起,因此没有特别的必要,建议不要直接访问
容器。
创建Bean的3种方式
使用构造器创建Bean实例
使用构造器来创建Bean实例是最常见的情况,如果不采用构造注入,Spring底层会调用Bean类的无参数构造器来创建实例,因此要求该Bean类提供无参数的构造器。
采用默认的构造器创建Bean实例,Spring对Bean实例的所有属性执行默认初始化,即所有的基本类型的值初始化为0或false;所有的引用类型的值初始化为null。
使用静态工厂方法创建Bean
使用静态工厂方法创建Bean实例时,class属性也必须指定,但此时class属性并不是指定Bean实例的实现类,而是静态工厂类,Spring通过该属性知道由哪个工厂类来创建Bean实例。
除此之外,还需要使用factory-method属性来指定静态工厂方法,Spring将调用静态工厂方法返回一个Bean实例,一旦获得了指定Bean实例,Spring后面的处理步骤与采用普通方法创建Bean实例完全一样。如果静态工厂方法需要参数,则使用
元素指定静态工厂方法的参数。
调用实例工厂方法创建Bean
实例工厂方法与静态工厂方法只有一个不同:调用静态工厂方法只需使用工厂类即可,而调用实例工厂方法则需要工厂实例。使用实例工厂方法时,配置Bean实例的
factory-bean: 该属性的值为工厂Bean的id
factory-method: 该属性指定实例工厂的工厂方法
若调用实例工厂方法时需要传入参数,则使用
元素确定参数值。
协调作用域不同步的Bean
当singleton作用域的Bean依赖于prototype作用域的Bean时,会产生不同步的现象,原因是因为当Spring容器初始化时,容器会预初始化容器中所有的singleton Bean,由于singleton Bean依赖于prototype Bean,因此Spring在初始化singleton Bean之前,会先创建prototypeBean——然后才创建singleton Bean,接下里将prototype Bean注入singleton Bean。
解决不同步的方法有两种
放弃依赖注入: singleton作用域的Bean每次需要prototype作用域的Bean时,主动向容器请求新的Bean实例,即可保证每次注入的prototype Bean实例都是最新的实例
利用方法注入: 方法注入通常使用lookup方法注入,使用lookup方法注入可以让Spring容器重写容器中Bean的抽象或具体方法,返回查找容器中其他Bean的结果,被查找的Bean通常是一个non-singleton Bean。Spring通过使用JDK动态代理或cglib库修改客户端的二进制码,从而实现上述要求
建议采用第二种方法,使用方法注入。为了使用lookup方法注入,大致需要如下两步
将调用者Bean的实现类定义为抽象类,并定义一个抽象方法来获取被依赖的Bean
在 元素中添加 子元素让Spring为调用者Bean的实现类实现指定的抽象方法
内部最核心的就是IOC了,动态注入,让一个对象的创建不用new了,可以自动的生产,这其
实就是利用java里的反射,反射其实就是在运行时动态的去创建、调用对象,Spring就是在运
行时,跟xml Spring的配置文件来动态的创建对象,和调用对象里的方法的 。
Spring还有一个核心就是AOP这个就是面向切面编程,可以为某一类对象 进行监督和控制
(也就是 在调用这类对象的具体方法的前后去调用你指定的 模块)从而达到对一个模块扩充的
功能。这些都是通过 配置类达到的
IOC(依赖注入)
Rod Johnson是第一个高度重视以配置文件来管理Java实例的协作关系的人,他给这种方式起
了一个名字:控制反转(Inverse of Control,IoC)。后来Martine Fowler为这种方式起了另一
个名称:依赖注入(Dependency Injection),因此不管是依赖注入,还是控制反转,其含义
完全相同。当某个Java对象(调用者)需要调用另一个Java对象(被依赖对象)的方 法时,在
传统模式下通常有两种做法.
原始做法:调用者主动创建被依赖对象,然后再调用被依赖对象的方法。
简单工厂模式:调用者先找到被依赖对象的工厂,然后主动通过工厂去获取被依赖对象,
最后再调用被依赖对象的方法。
注意上面的主动二字,这必然会导致调用者与被依赖对象实现类的硬编码耦合,非常不利于项
目升级的维护。使用Spring框架之后,调用者无需主动获取被依赖对象,调用者只要被动
接受Spring容器为调用者的成员变量赋值即可,由此可见,使用Spring后,调用者获取被依
赖对象的方式由原来的主动获取,变成了被动接受——所以Rod Johnson称之为控制反转。
另外从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量——
相当于为调用者注入它依赖的实例,因此Martine Fowler称之为依赖注入。
注入方式
1. 设置注入:IoC容器使用属性的setter方式注入被依赖的实例。
<property name="" ref="">
这种注入方式简单、直观,因而在Spring的依赖注入里大量使用。
优点:
2.构造注入:IoC容器使用构造器来注入被依赖的实例。
<constructor-arg ref="">
通俗来说,就是驱动Spring在底层以反射方式执行带指定参数的构造器,当执行带参数的构造
器时,就可利用构造器参数对成员变量执行初始化——这就是构造注入的本质。
优点:
AOP
为什么需要AOP
AOP(Aspect Orient Programming)也就是面向切面编程,作为面向对象编程的一种补充,已经成为一种比较成熟的编程方式。其实AOP问世的时间并不太长,AOP和OOP互为补充,面向切面编程将程序运行过程分解成各个切面。
AOP专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在JavaEE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。
使用AspectJ实现AOP
AspectJ是一个基于Java语言的AOP框架,提供了强大的AOP功能,其他很多AOP框架都借鉴或采纳其中的一些思想。其主要包括两个部 分:一个部分定义了如何表达、定义AOP编程中的语法规范,通过这套语法规范,可以方便地用AOP来解决Java语言中存在的交叉关注点的问题;另一个部 分是工具部分,包括编译、调试工具等。
AOP实现可分为两类
动态AOP实现: AOP框架在运行阶段动态生成AOP代理,以实现对目标对象的增强,以Spring AOP为代表
动态代理与静态代理区别
静态代理:由程序员创建,再对其编译。在程序运行之前.class文件已经存在了。静态代理:在程序运行时,运用反射的机制动态创建而完成。无需程序员手动编写代码,利用jdk的动态代理机制即可,不仅简化了编程工作,且提高了软件的可扩展性,因为java的反射机制可以生成任意类型的动态代理。
动态代理使用场景:不允许直接访问某些类,对访问要做特殊处理;或者对原始方法进行统一的扩展,例如日志的记录。
一般来说,静态AOP实现具有较好的性能,但需要使用特殊的编译器。动态AOP实现是纯Java实现,因此无须特殊的编译器,但是通常性能略差。
AOP的基本概念
关于面向切面编程的一些术语
切面(Aspect): 切面用于组织多个Advice,Advice放在切面中定义
连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出。在Spring AOP中,连接点总是方法的调用
通知(Advice):AOP框架在特定的切入点执行的 通知。处理有“around”、“before”和“after”等类型
切入点(Pointcut):可以插入 通知的连接点。简而言之,当某个连接点满足指定要求时,该连接点将被添加 通知,该连接点也就变成了切入点
目标对象(Target):目标对象就是被通知的对象,在AOP中,目标对象可以专心实现自身的业务逻辑,通知功能可以在程序运行期间自动引入。
代理(Proxy): 代理是目标对象中使用通知以后创建的对象,这个对象既拥有目标对象的全部功能,而且拥有通知提供的附加功能。
Spring的AOP支持
Spring中的AOP代理由Spring的IoC容器负责生成、管理,其依赖关系也由IoC容器负责管理。
为了在应用中使用@AspectJ支持,Spring需要添加三个库