Spring框架学习

    Spring是一个开源框架,为了解决企业应用开发的复杂性而创建的,但现在已经不止应用于企业应用,是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架

    从大小与开销两方面而言Spring都是轻量的

    通过控制反转(IoC)的技术达到松耦合的目的

    提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发

    包含并管理应用对象的配置和生命周期,这个意义上是一种容器

    将简单的组件配置、组合成为复杂的应用,这个意义上是框架

    

    Spring注入是指在启动Spring容器加载bean配置的时候,完成对变量的赋值行为常用的两种注入方式:设值注入、构造注入。   

构造注入:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd" >

<bean id="injectionService" class="main.java.com.imooc.ioc.injection.service.InjectionServiceImpl">

<constructor-arg name="injectionDao" ref="injectionDao"></constructor-arg>

</bean>

<bean id="injectionDao" class="main.java.com.imooc.ioc.injection.dao.InjectionDaoImpl"></bean>       

</beans>

设值注入:

<bean id="injectionService" class="main.java.com.imooc.ioc.injection.service.InjectionServiceImpl">

<property name="injectionDao" ref="injectionDao"></property>

</bean>

<bean id="injectionDao" class="main.java.com.imooc.ioc.injection.dao.InjectionDaoImpl"></bean> 



    Bean配置项:

Id   作用:在整个IOC容器中作为Bean的标识

Class   具体要实例化的类

Scope    范围、作用域

Constructor arguments    构造器的参数

Properties    属性

Autowiring mode    自动装配的模式

lazy-initialization mode    满加载模式

Initialization/destruction method    初始化和销毁的方法

    Bean的作用域scope

singleton:单例、指一个Bean容器中只存在一份

prototype:每次请求(每次使用)创建新的实例,destroy方式不生效

request:每次http请求创建一个实例且仅在当前request内有效

session:同上、每次http请求创建,当前session内有效

global session:基于portlet的web中有效(portlet定义了global session),如果是在web中,同session

    Bean的生命周期:定义、初始化、使用、销毁。

初始化:    方法一:实现org.springframework.beans.factory.InitializingBean接口

方法二:配置init_method

wKiom1icXgGA4y3iAAB6zVFIszY152.png


销毁:方法一:实现org.springframework.beans.factory.DisposableBean接口

方法二:配置destroy-method

配置全局默认初始化、销毁方法

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd" 

        default-init-method="defaultInit" default-destroy-method="defaultDestroy">

        <bean id="beanLifeCycle" class="main.java.com.imooc.lifecycle.BeanLifeCycle"></bean>    

</beans>

    Spring中提供了一些以Aware结尾的接口,实现了Aware接口的bean在被初始化之后,可以获取响应资源

通过Aware接口,可以对Spring响应资源进行操作(一定要谨慎操作)

为对Spring进行简单的扩展提供了方便的入口

    Bean的自动装配(Autowiring)

No:不做任何操作

byname:根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配

byType:如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配;如果存在多个该类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配;如果没有找到相匹配的bean,则什么事都不发生

Constructor:与byType方式类似,不同之处在于它应用于构造器参数。如果容器中没有找到与构造器参数类型一致的bean,那么抛出异常

    Resourves:

针对于资源文件的统一接口

UrlResource:URL对应的资源,根据一个URL地址即可构建

ClassPathResource:获取类路径下的资源文件

FileSystemResource:获取文件系统里面的资源

ServletContextResource:ServletContext封装的资源,用于访问ServletContext环境下的资源

InputStreamResource:针对于输入流封装的资源

ByteArrayResource:针对于字节数组封装的资源

    ResourceLoader:Resourves的加载类

wKiom1idHGGQwF18AAHH1jo6mEE304.png

    Bean管理的注解实现及例子

Classpath扫描与组件管理

类的自动检测与注册Bean

<context:annotation-config/>

@Component,@Repository,@Service,@Controller

@Required

@Autowired

@Qualifier

@Resource

    Classpath扫描与组件管理

从Spring3.0开始,Spring JavaConfig 项目提供了很多特性,包括使用java而不是XML定义bean,比如:

@Configuration(指把这个类当做配置文件使用),@Bean,@Import,@DependsOn

@Component是一个通用注解,可用于任何bean

@Repository,@Service,@Controller是更有针对性的注解

@Repository通常用于注解DAO类,即持久层

@Service通常用于注解Service类,即服务层

@Controller通常用于Controller类,即控制层(MVC)

    类的自动检测及Bean的注册

Spring可以自动检测类并注册Bean到ApplicationContext中

wKioL1idNmLy1nIOAAEUjXl28wU103.png

    <context:annotation-config/>

通过在基于XML的Spring配置如下标签(请注意包含上下文命名空间)

<context:annotation-config/>仅会查找在同一个applicationcontext中的bean注解

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:context="http://www.springframework.org/schema/context"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd   

        http://www.springframework.org/schema/context

        http://www.springframework.org/schema/context/spring-context.xsd">     

     <context:annotation-config></context:annotation-config>

</context:component-scan>

</beans>

为了能够检测这些类并注册响应的Bean,需要下面内容

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:context="http://www.springframework.org/schema/context"

    xsi:schemaLocation=

   "http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd   

        http://www.springframework.org/schema/context

        http://www.springframework.org/schema/context/spring-context.xsd">       

     <context:component-scan base-package="所需要扫描的包名"></context:component-scan>

</beans>

base-package=""   指扫描一个包下的所有类

<context:component-scan>(可以处理整个类的注解)包含<context:annotation-config>(处理方法或成员变量的注解),通常在使用前者后,不用再使用后者

AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor也会被包含进来

    使用过滤器进行自定义扫描

默认情况下,类被自动发现被注册bean的条件是:使用@Component,@Repository,@Service,@Controller注解或者使用@Component的自定义注解

可以通过过滤器修改上面的行为,如:下面例子的XMl配置忽略所有的@Repository注解并用"Stub"代替

wKiom1idPcjDsYQxAACo25mqDBY033.png

还可以使用use-default-filters="false"禁用自动发现与注册

过滤器的Type有多种类型

annotation:注解

assignable:具体某一个类的注解

aspectj:

regex:正则表达式、通配符

custom:自定义

    定义Bean

扫描过程中组件被自动检测,那么Bean名称是由BeanNameGenerator生成的(@Component,@Repository,@Service,@Controller都会有个name属性用于显式设置Bean Name)

可自定义bean命名策略,实现BeanNameGeneratoe接口,并一定要包含一个无参构造器

wKioL1idUBSDGoxrAABPEQYwVw0415.png

    作用域(Scope)

通常情况下自动查找的Spring组件,其scope是singleton,Spring2.5提供了一个标识scope的注解@Scope

也可以自定义scope策略,实现ScopeMetadataResolver接口并提供一个无参构造器

wKioL1idUnOz6qy6AABR-EKs66Y572.png

    代理方式

可以使用scoped-proxy属性指定代理,有三个值可选:no,interfaces,targetClass

<beans>

<context:component-scan base-package="org.example" scoped-proxy="interfaces"/>

</beans>

    @Required

@Required注解适用于bean属性的setter方法

这个注解仅仅表示,受影响的bean属性必须在配置时被填充,通过在bean定义或通过自动装配一个明确的属性值

wKioL1ideFuCBSGYAADGRavo0bc288.png

    @Autowired

可以将@Autowired注解为"传统"的setter方法

可用于构造器或成员变量

默认情况下,如果因找不到合适的bean将会导致autowiring失败抛出异常,可以通过下面的方式避免

@Autowired(required=false)

将required设置为false,即不是必要的,所以就能避免异常

每个类只能有一个构造器被标记为required=true

@Autowired的必要属性,建议使用@Required注解

    

可以使用@Autowired注解那些众所周知的解析依懒性接口,比如:BeanFactory,ApplicationContext,Environment,ResourceLoader,ApplicationEventPublisher,and MessageSource

可以通过添加注解给需要该类型的数组的字段或方法,以提供ApplicationContext中的所有特定类型的bean

    @Autowired

private List<BeanInterface> list;

可以用于装配key为String的Map

@Autowired

private Map<String, BeanInterface> map;//String 是bean的id,BeanInterface是bean的实例

如果希望数组有序,可以让bean实现org.springframework.core.Ordered接口或使用@Order注解


@Autowired是由Spring BeanPostProcessor处理的,所以不能在自己的BeanPostProcessor或BeanFactoryPostProcessor类型应用这些注解,这些类型必须通过XML或者Spring的@Bean注解加载

   

     @Qualifier

按类型自动装配可能多个bean实例的情况,可以使用Spring的@Qualifier注解缩小范围(或指定唯一),也可以用于指定单独的构造器参数或方法参数

可用于注解集合类型变量

在XML配置文件中使用Qualifier的方式

wKioL1igKmDBX3U7AAIxqzM2igg830.png

如果通过名字进行注解注入,主要使用的不是@Autowired(即使在技术上能够通过@Qualifier指定bean的名字),替代方式是使用JSR-250@Resource注解,它是通过其独特的名称来定义来识别特定的目标(这是一个与所声明的类型是无关的匹配过程)

因语义差异,集合或Map类型的bean无法通过@Autowired来注入,因为没有类型匹配到这样的bean,为这些bean使用@Resource注解,通过唯一名称引用集合或Map的bean

@Autowired适用于fields(字段),constructors(构造器),muti-argument methods(多参数方法)这些允许在参数级别使用@Qualifier注解缩小范围的情况

@Resource适用于成员变量、只有一个参数的setter方法,所以在目标是构造器或一个多参数方法时,最好的方式是使用qualifier

wKiom1igLpOwX0P6AAEw27m0Y2o919.png

wKioL1igLzHyE4n_AAIq9aclEiQ741.png

    基于java的容器注解

@Bean标识一个用于配置和初始化一个由SpringIoC容器管理的新对象的方法,类似于XML配置文件的<bean/>

可以再Spring的@Component注解的类中使用@Bean注解任何方法(仅仅是可以)


上一点中,通常使用的是@Configuration

@Configuration

public class AppConfig{

    @Bean

    public MyService myService(){

        return new MyServiceImpl();

    }

}

功能上等于:

<beans>

    <bean id="myService" class="com.XXX.XXX.MyServiceImpl">

</beans>


@Configuration

public class AppConfig{

    @Bean(service)    //自定义bean name

    public MyService myService(){

        return new MyServiceImpl();

    }

}

同时也支持init-method 和 destory-method


    使用@ImportResource和Value注解进行资源文件读取

在xml配置文件中使用的方式:

wKioL1igSMihL2gLAAKxix1amRM371.png

用注解的方式:

@Value("${url}")

private String url;

//@Value("${username}")//这样写的话,默认取到的值是该计算机操作数据的名称xujulong

@Value("${jdbc.username}")

private String username;

@Value("${password}")

private String password;

    @Resource

Spring还支持使用JSR-250@Resource注解的变量或setter方法

@Resource有一个name属性,并且默认Spring解释该值作为被注入bean的名称

如果没有显示地指定@Resource的name默认的名称是从属性名或者setter方法得出

注解提供的名字呗解析为一个bean的名称,这是由ApplicationContext的中的CommonAnnotationBeanPostProcessor发现并处理的

    @PostConstruct and @PreDestroy

CommonAnnotationBeanPostProcessor不仅能识别JSR-250中的生命周期注解@Resource,在Spring2.5中引入支持初始化回调和销毁回调,前提是CommonAnnotationBeanPostProcessor是Spring的ApplicationContext中注册的

    @Inject

@Inject等效于@Autowired,可以使用与类,属性,方法,构造器

    @Named

如果想使用特定名称进行依赖注入(当同一种类型的bean在Ioc容器中有多个的时候,想使用特定的那一个bean),使用@Named

@Named与@Component是等效的

    

AOP:Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能维护的一种技术

主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等

预编译:AspectJ

运行期动态代理(JDK动态代理、CGLib动态代理):SpringAOP、JbossAOP

    AOP几个相关概念

Joinpoint(连接点):程序执行过程中的某个特定的点

Advice(通知):在切面的某个特定的连接点上执行的动作

Pointcut(切入点):匹配连接点的断言,在AOP中通知和一个切入点表达式关联

Introduction(引入):在不修改类代码的前提下,为类添加新的方法和属性

Target Object(目标对象):被一个或者多个切面所通知的对象

AOP Proxy(AOP代理):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默认使用标准的JavaSE动态代理作为AOP代理,这使得任何接口(或者接口集)都可以被代理

Spring AOP中也可以使用CGLIB代理(如果一个业务对象并没有实现一个接口)

简化的Proxy定义:使用福字bean定义,以及内部bean定义


Spring所有的切面和通知其都必须放在一个<aop:config>内(可以配置包含多个<aop:config>元素),每一个<aop:congif>可以包含pointcut,advisor和aspect元素(它们必须按照这个顺序进行声明)


    Introductions

简介允许一个切面声明一个实现指定接口的通知对象,并且提供了一个接口实现类来代表这些对象

由<aop:aspect>中的<aop:declare-parents>元素声明该元素用于声明所匹配的类型拥有一个新的parent(因此得名)

schema-defined aspects只支持singleton model

    

    Advisors

advisor就像一个小的自包含的方面,只有一个advice

切面自身通过一个bean表示,并且必须实现某个advice接口,同时,advisor也可以很好的利用AspectJ的切入点表达式

Spring通过配置文件中<aop:advisor>元素支持advisor实际使用中,大多数情况下它会和transactional advice配合使用

为了定义一个advisor的优先级以便让advice可以有序,可以使用order属性来定义advisor的顺序

    

    ProxyFactoryBean

使用ProxyFactoryBean或者其它IoC相关类来创建AOP代理的最重要好处是通知和切入点也可以由IoC来管理

被代理类没有实现任何接口,使用CGLIB代理,否则JDK代理

通过设置proxyTargetClass为true,可强制使用CGLIB

如果目标类实现了一个(或者多个)接口,那么创建代理的类型将依赖ProxyFactoryBean的配置

如果ProxyFactoryBean的proxyInterfaces属性被设置为一个或者多个全限定接口名,基于JDK的代理将被创建

如果ProxyFactoryBean的proxyInterfaces属性没有被设置,但是目标类实现了一个(或者更多)接口,那么ProxyFactoryBean将自动检测到这个目标类已经实现了至少一个接口,创建一个基于JDK的代理

如果想,可以强制在任何情况下使用CGLIB,即使有接口

CGLIB代理的工作原理是在运行时生成目标类的子类,spring配置这个生成的子类委托方法调用到原来的目标

子类是用来实现Decotator模式,织入通知

CGLIB的代理对用户是透明的,需要注意:

final方法不能被通知,因为它们不能被覆盖

不用把CGLIB添加到classpath中,在Spring的JAR中有


    aspect

@AspectJ切面使用@Aspect注解配置,拥有@Aspect的任何bean将被Spring自动识别并应用

用@Aspect注解的类可以有方法和字段,他们也可能包括切入点(pointcut),通知(Advice)和引入(introduction)声明

@Aspect注解是不能够通过类路径自动检测发现的,所以需要配合使用@Component注释或者在xml配置bean

    pointcut

一个切入点通过一个普通的方法定义来提供,并且切入点表达式使用@Pointcut注解,方法返回类型必须为void

切入点表达式可以通过&&、||、和!进行组合,也可以通过名字引用切入点表达式

一个号的切入点应该包括以下几点:

    选择特定类型的连接点,如:execution,get,set,call,handler

    确定连接点范围,如:within,withincode

    匹配上下文信息,如:this,target,@annotation

    

    Around advice

环绕通知使用@Around注解来声明,通知方法的第一个参数必须是ProceedingJoinPoint类型

在通知内部调用ProceedingJoinPoint的proceed()方法会导致执行真正的方法,传入一个Object[]对象,数组中的值将会被作为参数传递给方法


    切面实例化模型

"perthis"切面通过制定@Aspect注解perthis子句实现

每个独立的service对象执行时都会创建一个切面实例

service对象的每个方法在第一次执行的时候创建切面实例,切面在service对象失效的同时失效


相关内容推荐