Spring相关知识
1. Spring基本概念
1.1 Spring降低java开发复杂性的关键方式:
基于POJO的轻量级和最小侵入编程;
通过依赖注入和面向接口实现松耦合;
基于切面和惯例进行声明式编程;
通过切面和模4板减少样本式代码。
1.2 依赖注入:降低组件之间的耦合程度
传统方式上,每个对象负责管理与自己相互协作的对象(即其依赖的对象)的引用,这会导致代码高度耦合且难以测试。
依赖注入会将所依赖的关系自动交给目标对象,而不是让对象自己取获取依赖。对依赖进行替换的一个最常用的方法就是在测试的时候使用mock实现。
创建应用组件之间协作的行为通常称之为装配,Spring可以使用多种装配方式如xml、java等,甚至包括自动发现bean并在这些bean中建立关联关系。通常,Spring通过应用上下文(ApplicationContext)装载bean的定义并将其组装起来。
1.3面向切面编程:可以将功能分离出来形成可重用的组件
面向切面编程是一种可以将软件系统的各个功能进行分离的一项技术。通常来说,像日志、事务管理、安全这样的系统服务经常融入到自身具有核心业务逻辑的组件中,这些系统服务我们称之为横切关注点,因为他们跨越系统的多个组件。但是这些系统服务融入到业务系统中,会导致代码的重复出现。
AOP能够使这些系统服务模块化,并以声明的方式应用至业务组件中,如此则业务组件具有更高的內聚性且会更加关注自身的业务逻辑,不需要涉及系统服务所带来的复杂性。借助AOP,我们可以将安全、事务、日志等关注点与核心业务逻辑相分离。
1.4 消除样板代码
Spring通过模板封装来消除样板式代码,例如Spring的jdbcTemplate可以使得执行数据库库访问操作时减少传统JDBC样板代码的生成。(注:实际中一般使用数据库中间件如hiberate,myBatis等来进行数据库访问,不会直接使用JDBC)。
1.5 Spring容器与应用上下文
在基于Spring的应用中,应用对象生存于Spring容器中,Spring容器负责创建对象,装配对象,配置对象并管理他们的生命周期。Spring容器并不只有一个,它具有多个容易实现,可以归为两类:bean工厂,应用上下文。通常应用上下文会更受欢迎些。例如ClassPathXmlApplicationContext可以在所有的类路径(包括JAR文件)下查找某xml文件。
1.6 Bean的生命周期
Spring中bean的生命周期要复杂许多,首先Spring对bean进行实例化,然后将值和bean的引用注入到bean对应的属性中,……,当bean准备就绪后就可以被应用程序使用。此时他们将一直停留在应用上下文中,直至该应用上下文被销毁。
当Spring容器关闭时,如果bean实现了DisposableBean接口,那么Spring将调用destory()方法来销毁,没有则调用自定义的销毁方法。
2. 自动化装配bean
2.1 在Spring中,对象无需自己查找或创建与其关联的其他对象。容器负责将需要相互协作的对象应用赋予各个对象。这种创建应用对象之间协作关系的行为通常称为装配,这也是依赖注入的本质。
2.2 Spring的三种装配机制
Xml文件中显式装配
Java中显式装配
隐式的bean发现机制和自动装配
通常建议是尽可能使用自动装配的机制,当必须要显示装配bean时,优先选择类型安全且比XML更强大的javaConfig,最后才考虑使用xml方式。(实际中还是先使用自动装配机制,显式装配时XML方式也比较多)。
2.3 Spring自动装配的两个内容:
组件扫描:Spring会自动发现应用上下文中所创建的bean
自动装配:Spring自动满足bean之间的依赖关系
通常,Spring在XML配置<context:component-scan>元素来开启组件扫描功能,默认会扫描与配置类相同的包路径,去寻找所有带有@Component注解的类。(还包括:@Controller, @Service, @Repository注解的类)
2.4 Bean的自动装配
Spring应用上下文会给所有的bean设定一个ID,如无明确指定,默认是把类名的首字母变为小写作为该bean的ID。
自动装配是Spring自动满足bean依赖的一种方法。在自动装配过程中,会在Spring应用上下文中寻找匹配某个bean需求的其他bean。为了声明要进行自动装配,我们可以借助@Autowired注解。(@Autowired与@Resource都可以用来装配bean)
@Autowired默认按类型装配(这个注解是属于spring的),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false);
@Resource(这个注解属于J2EE的),默认安照名称进行装配,名称可以通过name属性进行指定, 如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
例如:
@Resource(name="baseDao")
private BaseDao baseDao;
2.5 通过java/xml显式装配
当引用第三方组件装配到应用中时,就无法使用自动装配的方式。在显式装配时可采用javaConfig/xml两种方式。
2.5.1 javaConfig声明bean
javaConfig方式首先是采用@Configuration创建配置类,然后需要编写一个方法,在方法中创建所需类型的实例,然后给该方法添加@Bean注解。@Bean注解会告诉Spring该方法会产生一个对象,且该对象需要注册为Spring上下文中的Bean。
例如:
@bean
Public CompactDic sgtPeppers(){
Return newSgtPeppers();
}
在默认情况下,Spring中的Bean都是单例的。所以Spring会拦截所有对sgtPeppers()的调用并确保返回的是Spring所创建的bean。
2.5.2 xml声明bean
Xml文件中装配一个bean需要使用<bean>元素为根元素,类似于javaConfig中的@bean注解。
XML配置中,常使用构造器注入的方式来注入bean的引用,具体为<constructor-arg>元素。
例如
<bean id=”cdPlayer” class=”soundsystem.CDplayer”>
<constructor-argref=”compactDisc”/>
</bean>
2.5.3 字面量装配
字面量装配与装配引用的区别在于属性中去掉了“-ref”后缀。
例如:
Public BlankDisc(String title, String artist){
……
}
<bean id=” compactDisc” class=”soundsystem.BlankDisc”>
<constructor-argvalue=”Hearts Club Band”/>
<constructor-argvalue=”The Beatles”/>
</bean>
2.5.4 设置属性
通常来说,对于强依赖可以使用构造器注入,对于可选性的依赖使用属性注入。属性注入的标签是<property>
例如:
<bean id=”cdPlayer” class=”soundsystem.CDplayer”>
<propertyname=”compactDisc” ref=”compactDisc”/>
</bean>
字面量注入至属性中:
<property name=” title” value=” Hearts Club Band”/>
<property name=” artist” value=” The Beatles”/>
3. Bean的高级装配
3.1 Spring profile
3.1 条件化的bean声明
3.2 bean的作用域
默认情况下,Spring应用上下文中所有bean都是作为单例的形式创建的。也就是说不管给定的bean被注入到其他bean多少次,每次注入都是同一个实例。
有时候,如果某些类需要保持一些状态,那么重用是不安全的,这个时候将bean声明成单例的就会被污染,稍后重用的时候可能出现意想不到的问题。为此,Spring提供了多种作用域的定义:
单例:整个应用中,只会创建bean的一个实例;
原型:每次注入或者通过Spring应用上下文获取时,都会创建一个新的bean;
会话:在Web应用中,为每个会话创建一个bean;
请求:在Web应用中,为每个请求创建一个bean;
如果要选择其他的作用域,使用@scope注解来标识,例如@scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
4 面向切面的Spring
在软件开发中,散布于应用中多处的功能被称为横切关注点。通常来讲,这些横切关注点从概念上是与应用的业务逻辑相分离的,把这些横切关注点与业务逻辑相分离正是面向切面编程(AOP)所要解决的问题。AOP可以实现横切关注点与他们所影响的对象之间解耦。
4.1 面向切面的基本原理
通常来讲,如果要重用通用功能的话,最常见的方法是继承或委托。但是如果整个应用中都使用相同的基类,继承会导致一个脆弱的对象体系;而是用委托可能需要对委托对象进行复杂的调用。
切面则是取代继承和委托的另一种可选方案,在使用面向切面编程时,我们需要在一个地方定义通用功能,然后以声明的方式定义这个功能要以何种方式在何处应用,而无需修改受影响的类。
横切关注点可以被模块化为特殊的类,这些类称为切面。这样做一是每个关注点都集中在一个地方,二是服务代码更为简洁。
通知:在AOP中,切面的工作被称为通知,通知定义了切面是什么以及何时使用。
连接点:连接点是在应用执行过程中能够插入切面的一个点。这个店可以是调用方法时,抛出异常时,甚至修改某个字段时。
切点:切点的定义会匹配通知所要织入的一个或多个连接点。通常我们使用明确的类或方法名称,或者是正则表达式所匹配的类或方法来指定这些切点。
切面:切面就是通知和切点的结合。
引入:引入允许我们向现有的类中添加新的方法或属性。
织入:织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。
4.2 Spring对AOP的支持
Spring提供4种类型的AOP支持:
基于代理的经典SpringAOP;
纯POJO切面;
@AspectJ注解驱动的切面;
注入式AspectJ切面。
前三种都是SpringAOP实现的变体,