疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Spring学习与总结


 

Spring框架简介
Spring是一个开源框架,为了解决企业应用开发的复杂性而创建的,但现在已经不止应用与企业应用,是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
²  从大小和开销两方面而言Spring都是轻量的
²  通过控制反转(IoC)的技术达到松耦合的目的
²  提供面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发
²  包含并管理应用对象的配置和生命周期,这个意义上是一种容器
²  将简单的组件配置、组合成为复杂的应用,这个意义上是框架。
Spring开发简单、方便、快捷,应用于复杂JavaEE开发。
Spring作用:
²  容器
²  提供了多种技术的支持(JMS、MQ支持、UnitTest、…)
²  AOP(事务管理、日志等)
²  提供了众多方面应用的辅助类(JDBC Template等)
²  对主流应用框架(Hibernate等)提供了良好的支持。
使用范围:
²  构建企业应用(SpringMVC+Spring+Hibernate/ibatis)
²  单独使用Bean容器(Bean管理)
²  单独使用AOP进行切面处理
²  其他Spring功能,如对消息的支持等。
²  互联网中的应用。
框架
软件框架:通过指为实现某个业界标准或完成特定基本任务的软件组件规范,也指为了实现某个软件组件规范,提供规范所要求之基本功能的软件产品。
框架就是制定一套规范或者规则(思想),程序员在该规范或者规则(思想)下工作。即使用别人搭好的舞台,来做表演。
框架特点
²  半成品
²  封装了特定的处理流程和控制逻辑
²  成熟的、不断升级改进的软件
框架与类库的区别
²  框架一般是封装了逻辑、高内聚的,类库则是松散的工具组合
²  框架专注于某一领域,类库则是更通用的。
使用软件框架理由
²  软件系统日趋复杂
²  重用度高,开发效率和质量提高
²  软件设计人员要专注于对领域的了解,使需求分析更充分
²  易于上手,快速解决问题
 
IoC
接口
²  用于沟通的中介物的抽象化
²  实体把自己提供给外界的一种抽象化说明,用以内部操作分离出外部沟通方法,使其能被修改内部而不影响外界其他实体与其交互的方式
²  对应Java接口即声明,声明了哪些方法是对外公开提供的
²  在Java8中,接口可以拥有方法体。
面向接口编程
²  在结构设计中,分清层次集调用关系,每次只向外(上层)提供一组功能的接口,各层间仅依赖接口而非实现类
²  接口实现的变动不影响各层间的调用,这一点在公共服务中尤为重要。
²  面向接口编程中的接口是用于隐藏具体实现和实现多态性的组件。
IoC
²  IoC:控制反转,控制权的转移,应用程序本身不负责依赖对象的创建和维护,而是由外部容器复杂创建和维护
²  DI(依赖注入)是一种实现方式
²  目的:创建对象并且组装对象之间的关系。
获得依赖对象的过程被反转了。依赖注入:是由IoC容器在运行期间,动态地将某种依赖关系注入到对象中。
IoC:找IoC容器,容器返回对象,使用对象
IoC:IoC创建对象了,IoC隐藏了面向接口编程,IoC管理对象
Bean容器初始化
基础包:
²  Org.springframework.beans
²  Org.springframework.context
²  BeanFactory提供配置结构和基本功能,加载并初始化Bean
²  ApplicationContext保存了Bean对象并在Spring中被广泛使用
方式,ApplicationContext(初始化)
²  本地文件
²  Classpath
²  Web应用中依赖Servlet或Listener
Spring注入
Spring注入是指在启动Spring容器加载bean配置的时候,完成对变量的赋值行为
常用的两中注入方式:设值注入,构造注入
Bean
Bean常用的配置项
Id、Class、Scope、Constructor argument、Properties、Autowiring mode、lazy-initializationmode、Initialization/destructionmethod
Bean的作用域
Singleton:单例,指一个Bean容器中只存在一份
Prototype:每次请求(每次使用)创建新的实例,destory方式不生效
Request:每次http请求创建一个实例且仅在当前request内有效
Session:每次http请求创建,当前session内有效
Globalsession:基于portlet的web中有效(protlet定义了globalsession),如果是在web中,同session。
Bean的生命周期
定义、初始化、使用、销毁。
初始化:
²  实现org.springframework.beans.factory.InitializingBean接口,覆盖afterPropertiesSet方法
²  配置init-method
销毁:
²  实现org.springframework.beans.factory.DisposableBean接口,覆盖destory方法
²  配置destroy-method
配置全局默认初始化、销毁方法:在xml配置文件中,配置default-init-method和default-destroy-method
Aware接口
²  Spring中提供了一些以Aware结尾的接口,实现了Aware接口的bean在被初始化之后,可以获取相应的资源。
²  通过Aware接口,可以对Spring相应资源进行操作(一定要慎重)
²  为对Spring进行简单的扩展提供了方便的入口。
Bean的自动装配(Autowirting)
No:不做任何操作
Byname:根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配
byType:如果容器中存在一个与指定属性相同的bean,那么将与该属性自动装配,如果存在多个该类型的bean,那么抛出异常,并指出不能使用byType方式进行自动装配;如果没有找到相匹配的bean,则什么事都不发生。
Constructor:与byType方式类似,不同之处在于它应用与构造器参数。如果容器中没有找到与构造器参数类型一致的bean,则抛出异常。
 
Resource
针对于资源文件的同一接口
²  UrlResource:URL对应的资源,根据一个URL地址即可构建
²  ClassPathResource:获取类路径下的资源文件
²  FileSystemResource:获取类路径下的资源文件
²  ServletContextResource:ServletContext封装的资源,用于访问ServletContext环境下的资源
²  InputStreamResource:针对于输入流封装的资源
²  ByteArrayResource:针对于字节数组封装的资源
Bean管理
Classpath扫描与组件管理
从Spring3.0开始,Spring JavaConfig项目提供了很多特性,包括使用java而不是XML定义bean,如@Configuration,@Bean,@Import,@DependsOn
²  @Configuration是一个通用注解,可用于任何bean
²  @Component是一个通用注解,可用于任何bean
²  @Repository,@Service,@Controller是更有针对性的注解
²  @Repository:通常用于注解DAO类,即持久层
²  @Service:通常用于注解Service类,即服务层
²  @Controller:通常用于Controller类,即控制层(MVC)
元注解(Meta-annotations)
许多Spring提供的注解可以作为自己的代码,即“元数据注解“,元注解是一个简单的注解,可以应用到另一个注解。除了value(),元注解还可以有其他的属性,允许定制。
Spring可以自动检测类并注册Bean到ApplicationContext中,可以使用过滤器进行自定义扫描。
定义Bean
扫描过程中,组件被自动检测,那么Bean名称是由BeanNameGenerator生成的(@Component,@Repository,@Service,@Controller都会有个name属性用于显示设置Bean Name),可自定义bean命名策略,实现BeanNameGenerator接口,并一定要包含一个无参构造函数器。
作用域(Scope)
通常情况下,自动查找的Spring组件,其Scope是singleton,Spring2.5提供了一个标识scope的注解@Scope,也可以自定义scope策略,实现ScopemetadataResolver接口并提供一个无参构造函数。
代理方式:可以使用scoped-proxy属性指定代理,有三个值可选:no、interfaces、targetClass。
²  @Required注解:适应于bean属性的setter方法,这个注解仅仅表示,受影响的bean属性必须在配置时被填充,通过在bean定义或通过自动装配一个明确的属性值。
²  @Autowired注解:可以将@Autowired注解为“传统”的setter方法,可用于构造器或成员变量;默认情况下,如果因找不到合适的bean将会导致autowiring失败抛出异常,可以通过设置@Autowired(required-false)来避免;每个类只能有一个构造器被标记为required=true;@Autowired的必要属性,建议使用@Required注解。
@Autowired注解:可以使用@Autowired注解那些众所周知的解析依赖性接口,如:BeanFactory,ApplicationContext,Environmet,ResourceLoader,ApplicationEventPublisher,and MessageSource;可以通过添加注解给需要该类型的数组的字段或方法,以提供ApplicationContext中的所有特定类型的bean,可以用于装配key为String的Map。如果希望数组有序,可以让bean实现,org.springframework.core.Ordered接口或使用的@Order注解。
@Autowired是由SpringBeanPostProcessor处理的,所以不能在自己的BeanPostProcessor或BeanFactoryPostProcessor类型应用这些注解,这些类型必须通过XML或者Spring的@Bean注解加载。
²  @Qualifier注解
n  按类型自动装配可能多个bean实例的情况,可以使用Spring的@Qualifier注解缩小范围(或指定唯一),也可以用于指定单独的构造器参数或方法参数
n  可用于注解集合类型变量。
n  如果通过名字进行注解注入,主要使用的不是@Autowired(即使在技术上能够通过@Qualifier指定bean的名字),替代方式是使用JSR-250@Resource注解,它是通过其独特的名称来定义识别特定的目标(这是一个与声明的类型是无关的匹配过程)
n  因语义差异,集合和Map类型的bean无法通过@Autowired来注入,因为没有类型匹配到这样的bean,为这些bean使用@Resource注解,通过唯一名称引用集合或Map的bean
n  @Autowired适用于fields,constructors,multi-argument methods这些允许在参数级别使用@Qualifier注解缩小范围的情况
n  @Resource适用于成员变量,只有一个参数的setter方法,所以在目标是构造器或一个多参数方法时,最好的方式是使用qualifiers
n  也可以定义自己的qualifier注解并使用
 
基于Java容器的注解
@Bean标识一个用于配置和初始化一个由SpringIoC容器管理的新对象的方法,类似于XML配置文件的<bean/>
可以在Spring的@Component注解的类中使用@Bean注解任何方法(仅仅是可以),上一点中,通常使用@Configuration
@Bean支持自定义Bean name,方法为@Bean(name= “myFoo”)
可以有init-method和destroy-method方法。@Bean(init-method=”init“);
CustomAutowireConfigurer
CustomAutowireConfigurer是BeanFactoryPostProcessor的子类,通过它可以注册自己的qualifier注解类型(即没有使用Spring的@Qualifier注解);该AutowireCandidateResolver决定自动装配的候选者:
²  每个bean定义的autowire-candidate值
²  任何<bean/>中的default-autowire-candidates
²  @Qualifier注解及使用CustomAutowireConfigurer的自定义类型
@Resource
²  Spring还支持使用JSR-250@Resource注解的变量或setter方法,这是一种在Java EE5和6的通用模式,Spring管理的对象也支持这种模式。
²  @Resource有一个name属性,并且默认Spring解释该值作为被注入bean的名称。
²  如果没有显式地指定@Resource的name,默认的名称是从属性名或者setter方法得出
²  注解提供的名字被解析为一个bean的名称,这是由ApplicationContext中的CommonAnnotationBeanPostProcessor发现并处理的。
@PostConstruct和@PreDestory
²  CommonAnnotationBeanPostProcessor不仅能识别JSR-250中的生命周期注解@Resource,在Spring2.5中引入支持初始化回调和销毁回调,前提是CommonAnnotationBeanPostProcessor是Spring的ApplicationContext中注册的。
²  使用JSR330标准注解
²  从Spring3.0开始支持JSR330标准注解(依赖注入注解),其扫描方式与Spring注解一致,使用JSR330需要依赖javax.inject包。
²  @Inject:@Inject等效于@Autowired,可以使用类、属性、方法、构造器。
²  如果想使用特定名称进行依赖注入,使用@Named,@Named与@Component是等效的。
 
AOP面向切向编程
AOP(Aspect OrientedProgramming):为面向切面编程,通过预编译方式与运行期动态代理实现程序功能的统一维护的一种技术。主要功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
AOP实现方式:
预编译:AspectJ
运行期动态代理(JDK动态代理,CGLib动态代理):SpringAOP、JbossAOP
 
AOP相关概念如下:
名称
说明
切面(Aspect)
一个关注点的模块化,这个关注点可能会横切多个对象
连接点(Joinpoint)
程序执行过程中的某个特定的点
通知(Advice)
在切面的某个特定的连接点上执行的动作
切入点(Pointcut)
匹配连接点的断言,在AOP中通知和一个切入点表达式关联
引入(introduction)
在不修改类代码的前提下,为类添加新的方法和属性
目标对象(Target Object)
被一个或者多个切面所通知的对象
AOP代理(AOP Proxy)
AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)
织入(Weaving)
把切面连接到其他的应用程序类型或者对象上,并创建一个被通知的对象,分为:编译时织入,类加载时织入,执行时织入
Advice类型
名称
说明
前置通知
(Before advice)
在某连接点(join point)之前执行的通知,但不能阻止连接点前的执行(除非它抛出一个异常)
返回后通知
(After returning advice)
在某连接点(join point)正常完成后执行的通知
抛出异常后通知
(After throwing advice)
在方法抛出异常退出时执行的通知
后通知
(After(finally)advice)
当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)
环绕通知
(Around Advice)
包围一个连接点(join point)的通知
Spring框架中AOP的用途
²  提供了声明式的企业服务,特别是EJB的替代服务的声明
²  允许用户定制自己的方面,已完成OOP与AOP的互不使用
Spring的AOP实现
²  纯java实现,无需特殊的编译过程,不需要控制类加载器层次
²  目前只支持方法执行连接点(通知Spring Bean的方法执行)
²  不是为了提供最完整的AOP实现(尽管它非常强大);而是侧重于提供一种AOP实现和Spring IoC容器之间的整合,用于帮助解决企业应用中常见问题
²  Spring AOP不会与AspectJ竞争,从而提供综合全面的AOP解决方案。
有接口和无接口的SpringAOP实现区别
²  Spring AOP默认使用标准的JavaSE动态代理作为AOP代理,这使得任何接口(或者接口集)都可以被代理;
²  Spring AOP中也可以使用CGLIB代理(如果一个业务对象并没有实现一个接口)。
Spring所有的切面和通知器都必须放在一个<aop:config>内(可以配置包含多个<aop:config>元素),每一个<aop:config>可以包含pointcut,advisor和aspect元素(它们必须按照这个顺序进行声明)
<aop:config>风格的配置大量使用了Spring的自动代理机制。
Pointcut
²  Execution(public * *(..)) 切入点为执行所有public方法时
²  Execution(* set*(..)) 切入点为执行所有set开始的方法时
²  Execution(* com.xyz.service.AccountServiecr.*(..)) 切入点为执行AccountService类中的所有方法时
²  Execution(* com.xyz.service..(..)) 切入点为执行com.xyz.service包下的所有方法时
²  Execution(* com.xyz.service..(..)) 切入点为执行com.xyz.service包及其子包下的所有方法时
²  Within(com.xyz.service.*)(only in Spring AOP)
²  Within(com.xyz.service..*)(only in Spring AOP) within用于匹配指定类型内的方法执行
²  This(com.xyz.service.AccountService)(only in Spring AOP) this用于匹配当前AOP代理对象类型的方法
²  Target(com.xyz.service.AccountService)(only in Spring AOP) target用于匹配当前目标对象类型的执行方法
²  Args(java.io.Serializable)(only in Spring AOP)
²  @target(org.springframework.transaction.annotation.Transactional)(onlyin spring AOP)
²  @within(org.springframework.transaction.annotation.Transactional)(onlyin Spring AOP)
²  @annotation(org.springframework.transaction.transaction.annotation.Transactional)(onlyin Spring AOP) aras用于匹配当前执行的方法传入的参数为指定类型的执行方法。
²  @args(com.xyz.security.Classified)(only in Spring AOP)
²  Bean(tradeService)(only in Spring AOP)
²  Bean(*Service)(only in Spring AOP)
²  After throwing advice:使用throwing属性来指定可被传递的异常的参数名称
Aroundadvice
通知方法的第一个参数必须是ProceedingJoinPoint类型
Introductions:简介允许一个切面声明一个实现指定接口的通知对象,并且提供了一个接口实现类来代表这些对象;由<aop:aspect>中的<aop:declare-parents>元素声明该元素用于声明所匹配的类型拥有一个新的parent(因此得名)
Schema-definedaspect只支持singleton model
Advisors
²  Advisors就像一个小的自包含的方面,只有一个advice
²  切面自身通过一个bean表示,并且必须实现某个advice接口,同时advisor也可以很好的利用AspectJ的切入点表达式
²  Spring通过配置文件中<aop:advisor>元素支持advisor实际使用中,大多数情况下它会和transaction advice配合使用
²  为了定义一个advisor的优先级以便让advice可以有序,可以使用order属性来定义advisor的顺序
AspectJ
²  @AspectJ的风格类似纯java注解的普通java类
²  Spring可以使用AspectJ来做切入点解析
²  AOP的运行时仍旧是纯Spring AOP,对AspectJ的编译器或者织入无依赖性
Spring中配置AspectJ
²  对@AspectJ支持可以使用XML或Java风格的配置
²  确保AspectJ的aspectjweaver.jar库包含在应用程序(1.68或更高版本)的classpath中
@AspectJ切面使用@Aspect注解配置,拥有@Aspect的任何bean将被Spring自动识别并应用。
用@Aspect注解的类可以有方法和字段,他们也可能包括切入点(pointcut),通知(Advice)和引入(introduction)声明。
@Aspect注解是不能够通过类路径自动检测发现的,所以需要配合使@Component注释或者xml配置bean。
一个类中的@Aspect注解标识它为一个切面,并且将自己从自动代理中排除。
一个切入点通过一个普通的方法来定义提供,并且切入点表达式使用@Pointcut注解,方法返回类型必须为void。
定义一个名为“anyOldTransfer”,这个切入点将匹配任何名为“transfer”的方法的执行
切入点支持的方式
Execution
匹配方法执行的连接点
Within
限定匹配特定类型的连接点
This
匹配特定连接点的bean引用是指定类型的实例的限制
Target
限定匹配特定连接点的目标对象给指定类型的实例
Args
限定匹配特定连接点的参数是给定类型的实例
@target
限定匹配特定连接点的类执行对象的具有给定类型的注解
@args
限定匹配特定连接点实际传入参数的类型具有给定类型的注解
@within
限定匹配到内具有给定的注释类型的连接点
@annotation
限定匹配特定连接点的主体具有给定的注解
组合pointcut
切入点表达式可以通过&&、||和!进行组合,也可以通过名字引用切入点表达式,通过组合,可以建立更加复杂的切入点表达式。
定义良好的pointcuts
AspectJ是编译器的AOP
检查代码并匹配连接点与切入点的代价是昂贵的
一个好的切入点应该包括以下几点:
²  选择特定类型的连接点,如execution,get,set,call,handler
²  确定连接点范围,如within,withincode
²  匹配上下文信息,如this,target,@annotation