spring4.x
2018-01-31 14:41:18 102 举报
AI智能生成
spring 相关的知识
作者其他创作
大纲/内容
4 IoC容器概述
IoC概述
IoC控制反转:某一接口具体实现类的选择控制权从调用类中移除,转交给第三方决定
IoC的类型:
构造函数注入:
属性注入:
接口注入:把调用类的所有依赖注入方法抽取到一个接口中,调用类通过实现接口的方法完成注入。
构造函数注入:
属性注入:
接口注入:把调用类的所有依赖注入方法抽取到一个接口中,调用类通过实现接口的方法完成注入。
资源访问利器
1.资源抽象接口:Resource 它的实现类有:
WriteableResource : 可写资源接口,是spring3.1新增的,
有两个实现类(FileSystemResource和PathResource)
ByteArrayResource : 二进制数据表示的资源
ClassPathResource :类路径下的资源
FileSystemResource : 文件系统资源
InputStreamResource : 对应一个InputStream流
ServletContextResource : Web容器上下文中的资源
UrlResource : 网络资源
PathResource : spring4.0提供的,封装了java.net.URL、java.nio.file.Path、文件系统资源。
2.资源文件可以通过EncodedResource对资源进行编码
WriteableResource : 可写资源接口,是spring3.1新增的,
有两个实现类(FileSystemResource和PathResource)
ByteArrayResource : 二进制数据表示的资源
ClassPathResource :类路径下的资源
FileSystemResource : 文件系统资源
InputStreamResource : 对应一个InputStream流
ServletContextResource : Web容器上下文中的资源
UrlResource : 网络资源
PathResource : spring4.0提供的,封装了java.net.URL、java.nio.file.Path、文件系统资源。
2.资源文件可以通过EncodedResource对资源进行编码
1,资源地址表达式:
----------------------------------------------------------------------------------------------
地址前缀 示例 对应资源类型
----------------------------------------------------------------------------------------------
classpath: classpath: me/leifgao/beans.xml classpath:和classpath:/等价。资源文件 可以在标准的文件系统中,也可以在jar或zip包中
file: file:/me/leifgao/beans.xml 使用UrlResource从文件系统中拿
http:// http://leifgao.me/beans.xml 使用UrlResource从web服务器中加载
ftp:// ftp://leifgao.me/beans.xml 使用UrlResource从Ftp服务器中加载
没有前缀 me/leifgao/beans.xml 根据ApplicationContext具体实现类采 用对应的Resource
2, classpath: 和 classpath*: 的区别
如果有多个JAR包,classpath:只会在第一个加载的包下查找;classpath*:会扫描所有的JAR包,多次加载
3,Ant风格的资源路径支持的3中匹配符
?:匹配文件名中的一个字符 *:匹配文件名中任意个字符 **:匹配多层路径
4, PathMatchingResourcePatternResolver是spring提供的资源加载实现类
----------------------------------------------------------------------------------------------
地址前缀 示例 对应资源类型
----------------------------------------------------------------------------------------------
classpath: classpath: me/leifgao/beans.xml classpath:和classpath:/等价。资源文件 可以在标准的文件系统中,也可以在jar或zip包中
file: file:/me/leifgao/beans.xml 使用UrlResource从文件系统中拿
http:// http://leifgao.me/beans.xml 使用UrlResource从web服务器中加载
ftp:// ftp://leifgao.me/beans.xml 使用UrlResource从Ftp服务器中加载
没有前缀 me/leifgao/beans.xml 根据ApplicationContext具体实现类采 用对应的Resource
2, classpath: 和 classpath*: 的区别
如果有多个JAR包,classpath:只会在第一个加载的包下查找;classpath*:会扫描所有的JAR包,多次加载
3,Ant风格的资源路径支持的3中匹配符
?:匹配文件名中的一个字符 *:匹配文件名中任意个字符 **:匹配多层路径
4, PathMatchingResourcePatternResolver是spring提供的资源加载实现类
BeanFactory和ApplicationContext
1,BeanFactory扩展接口 :
ListableBeanFactory : 定义了访问容器中Bean基本信息方法,如查看Bean的个数、获取某一类型Bean 的配置名、查看容器中是否包括某一Bean等方法。
HierarchicalBeanFactory : 父子级联IoC容器的接口,子容器可以通过接口方法访问父容器
ConfigurableBeanFactory : 增强了IoC容器的可定制性,定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法。
AutowireCapableBeanFactory : 定义了想容器中的Bean按照某种规则(如按照名字匹配、按照类型匹配等)进行自动装配的方法。
SingletonBeanRegistry : 定义了允许在运行期间向容器注册单实例Bean的方法
BeanDefinitionRegistry : Spring配置文件中每一个<bean>节点元素在Spring容器中都通过一个BeanDefinition对象表示,它描述了Bean的配置信息。该接口提供了向容器中手工注册BeanDefinition对象的方法
ListableBeanFactory : 定义了访问容器中Bean基本信息方法,如查看Bean的个数、获取某一类型Bean 的配置名、查看容器中是否包括某一Bean等方法。
HierarchicalBeanFactory : 父子级联IoC容器的接口,子容器可以通过接口方法访问父容器
ConfigurableBeanFactory : 增强了IoC容器的可定制性,定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法。
AutowireCapableBeanFactory : 定义了想容器中的Bean按照某种规则(如按照名字匹配、按照类型匹配等)进行自动装配的方法。
SingletonBeanRegistry : 定义了允许在运行期间向容器注册单实例Bean的方法
BeanDefinitionRegistry : Spring配置文件中每一个<bean>节点元素在Spring容器中都通过一个BeanDefinition对象表示,它描述了Bean的配置信息。该接口提供了向容器中手工注册BeanDefinition对象的方法
1,ApplicationContext的类继承体系:
ApplicationEventPublisher : 让容器拥有发布应用上下文的功能。实现了ApplicationListener事件监听接口的Bean可以接收到容器事件。
MessageSource : 为应用提供il18n国际化消息访问功能
ResourcePatternResolver : 所有的ApplicationContext实现类都实现了,通过Ant风格的资源文件路径装载Spring配置文件
LifeCycle : 该接口提供了start() 和 stop()方法,用于控制异步处理过程
ConfigurableApplicationContext :新增了两个方法,refresh()和close()
2,BeanFactory在初始化容器时,并没有实例化Bean,直到第一次访问时,才实例化目标bean
ApplicationContext则在初始化时,就实例化了所有的Bean
3,@Configuration注解POJO既可以提供Bean,Spring提供的实现类AnnotationConfigApplicationC ontext
4,WebApplicationContext类体系结构
WebApplicationContext中定义了一个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文启动时,webapplicationcontext已此为键放置在ServletContext中。
ConfigurableWebApplicationContext扩展了WebApplicationContext,允许通过配置的方式实例化,有两个重要的方法:
setServletContext(ServletContext servletContext):为spirng设置Web应用上下文,方便两者整合
setConfigLocations(String[] configLocations):设置Spring配置文件地址。
5,父子容器
通过HierarchicalBeanFactory接口,可以建立父子容器,子容器可以访问父容器中的bean,但父容器不能访问子容器的Bean。容器中的id必须唯一,但子容器可以拥有和父容器id相同的bean。
例如Spring MVC中,展现层Bean位于一个子容器中,而业务层和持久层的Bean位于父容器中。这样,展现层的Bean就可以引用业务层和持久层的Bean,而业务层和持久层的Bean则看不到展现层的Bean。
ApplicationEventPublisher : 让容器拥有发布应用上下文的功能。实现了ApplicationListener事件监听接口的Bean可以接收到容器事件。
MessageSource : 为应用提供il18n国际化消息访问功能
ResourcePatternResolver : 所有的ApplicationContext实现类都实现了,通过Ant风格的资源文件路径装载Spring配置文件
LifeCycle : 该接口提供了start() 和 stop()方法,用于控制异步处理过程
ConfigurableApplicationContext :新增了两个方法,refresh()和close()
2,BeanFactory在初始化容器时,并没有实例化Bean,直到第一次访问时,才实例化目标bean
ApplicationContext则在初始化时,就实例化了所有的Bean
3,@Configuration注解POJO既可以提供Bean,Spring提供的实现类AnnotationConfigApplicationC ontext
4,WebApplicationContext类体系结构
WebApplicationContext中定义了一个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文启动时,webapplicationcontext已此为键放置在ServletContext中。
ConfigurableWebApplicationContext扩展了WebApplicationContext,允许通过配置的方式实例化,有两个重要的方法:
setServletContext(ServletContext servletContext):为spirng设置Web应用上下文,方便两者整合
setConfigLocations(String[] configLocations):设置Spring配置文件地址。
5,父子容器
通过HierarchicalBeanFactory接口,可以建立父子容器,子容器可以访问父容器中的bean,但父容器不能访问子容器的Bean。容器中的id必须唯一,但子容器可以拥有和父容器id相同的bean。
例如Spring MVC中,展现层Bean位于一个子容器中,而业务层和持久层的Bean位于父容器中。这样,展现层的Bean就可以引用业务层和持久层的Bean,而业务层和持久层的Bean则看不到展现层的Bean。
Bean的生命周期
一,BeanFactory中Bean生命周期的完整过程:
1,bean实例化之前,调用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()
2,调用Bean构造函数或工厂方法实例化Bean
3,bean实例化之后,调用InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
4,Bean设置属性信息前,调用InstantiationAwareBeanPostProcessor#postProcessPropertyValues()
5,调用Bean的属性设置方法设置属性值
6,调用BeanNameAware#setBeanName()接口方法,将配置文件中该Bean对应的名称设置到Bean中
7,调用BeanFactoryAware#setBeanFactory(),将BeanFactory容器实例设置到Bean中
8,BeanPostProcessor#postProcessBeforeInitialization(Object bean, String beanName)
9,InitializingBean#afterPropertiesSet()
10,执行init-method属性定义的方法
11,BeanPostProcessor#postProcessAfterInitialization(Object bean, String beanName)
12,如果Bean的作用范围为scope="prototype",将Bean返回给调用者,调用者负责管理Bean的后续生命周期,Spring不在管理这个Bean的声明周期
13,如果Bean的作用范围为scope="singleton",则将Bean放入到Spring IoC容器的缓存池,并将Bean引用返回给调用者,Spring继续管理这些Bean的生命周期
14,对于13,当容器关闭时,调用DisposableBean#afterPropertiesSet()方法
15,对于13,调用destroy-method属性指定的方法
二,bean生命周期方法的分类:
1,Bean自身的方法:例如,Bean构造函数实例化Bean,调用Setter设置Bean属性值,init-method和destroy-method所指定的方法;
2,Bean级生命周期接口方法:例如,BeanNameAware、BeanFactoryAware、InitializingBean和DisposableBean。这些接口的方法由Bean类直接实现
3,容器级生命周期接口方法:例如,InstantiationAwareBeanPostProcessor和BeanPostProcessor,一般称为后处理器,后处理器接口一般不由Bean本身实现,独立于Bean,后处理器的影响是全局性的。
三,如果要实现多个后处理器,需要多个后处理器同时实现org.springframework.core.Ordered接口,按照特定的顺序来执行这些后处理器。
1,bean实例化之前,调用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()
2,调用Bean构造函数或工厂方法实例化Bean
3,bean实例化之后,调用InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
4,Bean设置属性信息前,调用InstantiationAwareBeanPostProcessor#postProcessPropertyValues()
5,调用Bean的属性设置方法设置属性值
6,调用BeanNameAware#setBeanName()接口方法,将配置文件中该Bean对应的名称设置到Bean中
7,调用BeanFactoryAware#setBeanFactory(),将BeanFactory容器实例设置到Bean中
8,BeanPostProcessor#postProcessBeforeInitialization(Object bean, String beanName)
9,InitializingBean#afterPropertiesSet()
10,执行init-method属性定义的方法
11,BeanPostProcessor#postProcessAfterInitialization(Object bean, String beanName)
12,如果Bean的作用范围为scope="prototype",将Bean返回给调用者,调用者负责管理Bean的后续生命周期,Spring不在管理这个Bean的声明周期
13,如果Bean的作用范围为scope="singleton",则将Bean放入到Spring IoC容器的缓存池,并将Bean引用返回给调用者,Spring继续管理这些Bean的生命周期
14,对于13,当容器关闭时,调用DisposableBean#afterPropertiesSet()方法
15,对于13,调用destroy-method属性指定的方法
二,bean生命周期方法的分类:
1,Bean自身的方法:例如,Bean构造函数实例化Bean,调用Setter设置Bean属性值,init-method和destroy-method所指定的方法;
2,Bean级生命周期接口方法:例如,BeanNameAware、BeanFactoryAware、InitializingBean和DisposableBean。这些接口的方法由Bean类直接实现
3,容器级生命周期接口方法:例如,InstantiationAwareBeanPostProcessor和BeanPostProcessor,一般称为后处理器,后处理器接口一般不由Bean本身实现,独立于Bean,后处理器的影响是全局性的。
三,如果要实现多个后处理器,需要多个后处理器同时实现org.springframework.core.Ordered接口,按照特定的顺序来执行这些后处理器。
二,ApplicationContext中Bean生命周期的完整过程:
1,BeanFactoryPostProcessor#postProcessBeanFactory()对工厂定义信息进行后处理
2,调用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()
3,实例化
4,bean实例化之后,调用InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
5,Bean设置属性信息前,调用InstantiationAwareBeanPostProcessor#postProcessPropertyValues()
6,调用Bean的属性设置方法设置属性值
7,调用BeanNameAware#setBeanName()接口方法,将配置文件中该Bean对应的名称设置到Bean中
8,调用BeanFactoryAware#setBeanFactory(),将BeanFactory容器实例设置到Bean中
9,调用ApplicationContextAware的setApplicationContext()方法
10,调用BeanPostProcessor的postProcessBeforeInitialization()方法
11,调用InitializingBean的afterPropertiesSet()方法
12,通过init-method属性配置的初始化方法
13,调用BeanPostProcessor的postProcessAfterInitialization()方法
14,如果Bean的作用范围为scope="prototype",将Bean返回给调用者,调用者负责管理Bean的后续生命周期,Spring不在管理这个Bean的声明周期
15,如果Bean的作用范围为scope="singleton",则将Bean放入到Spring IoC容器的缓存池,并将Bean引用返回给调用者,Spring继续管理这些Bean的生命周期
16,对于15,当容器关闭时,调用DisposableBean#afterPropertiesSet()方法
17,对于15,调用destroy-method属性指定的方法
二,bean生命周期方法的分类:
1,Bean自身的方法:例如,Bean构造函数实例化Bean,调用Setter设置Bean属性值,init-method和destroy-method所指定的方法;
2,Bean级生命周期接口方法:例如,BeanNameAware、BeanFactoryAware、InitializingBean和DisposableBean。这些接口的方法由Bean类直接实现
3,容器级生命周期接口方法:例如,InstantiationAwareBeanPostProcessor和BeanPostProcessor,一般称为后处理器,后处理器接口一般不由Bean本身实现,独立于Bean,后处理器的影响是全局性的。
三,如果要实现多个后处理器,需要多个后处理器同时实现org.springframework.core.Ordered接口,按照特定的顺序来执行这些后处理器。
1,BeanFactoryPostProcessor#postProcessBeanFactory()对工厂定义信息进行后处理
2,调用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()
3,实例化
4,bean实例化之后,调用InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
5,Bean设置属性信息前,调用InstantiationAwareBeanPostProcessor#postProcessPropertyValues()
6,调用Bean的属性设置方法设置属性值
7,调用BeanNameAware#setBeanName()接口方法,将配置文件中该Bean对应的名称设置到Bean中
8,调用BeanFactoryAware#setBeanFactory(),将BeanFactory容器实例设置到Bean中
9,调用ApplicationContextAware的setApplicationContext()方法
10,调用BeanPostProcessor的postProcessBeforeInitialization()方法
11,调用InitializingBean的afterPropertiesSet()方法
12,通过init-method属性配置的初始化方法
13,调用BeanPostProcessor的postProcessAfterInitialization()方法
14,如果Bean的作用范围为scope="prototype",将Bean返回给调用者,调用者负责管理Bean的后续生命周期,Spring不在管理这个Bean的声明周期
15,如果Bean的作用范围为scope="singleton",则将Bean放入到Spring IoC容器的缓存池,并将Bean引用返回给调用者,Spring继续管理这些Bean的生命周期
16,对于15,当容器关闭时,调用DisposableBean#afterPropertiesSet()方法
17,对于15,调用destroy-method属性指定的方法
二,bean生命周期方法的分类:
1,Bean自身的方法:例如,Bean构造函数实例化Bean,调用Setter设置Bean属性值,init-method和destroy-method所指定的方法;
2,Bean级生命周期接口方法:例如,BeanNameAware、BeanFactoryAware、InitializingBean和DisposableBean。这些接口的方法由Bean类直接实现
3,容器级生命周期接口方法:例如,InstantiationAwareBeanPostProcessor和BeanPostProcessor,一般称为后处理器,后处理器接口一般不由Bean本身实现,独立于Bean,后处理器的影响是全局性的。
三,如果要实现多个后处理器,需要多个后处理器同时实现org.springframework.core.Ordered接口,按照特定的顺序来执行这些后处理器。
5 在IoC容器中装配Bean
Spring配置概述
Spirng容器高层视图
Spring容器启动成功,需要具备三个条件:
1,spring框架的包都已经在classpath中
2,应用程序提供了完整的Bean配置信息
3,Bean的类都已经放到应用程序的类路径下
1,spring框架的包都已经在classpath中
2,应用程序提供了完整的Bean配置信息
3,Bean的类都已经放到应用程序的类路径下
Bean配置信息是Bean的元数据信息,由一下4个方面组成:
1,bean的实现类
2,bean的属性信息,如数据源源的连接数、用户名、密码
3,bean的依赖关系,Spring根据依赖关系配置完成Bean之间的装配
4,bean的行为配置,如生命周期范围及生命周期各过程的回调函数
1,bean的实现类
2,bean的属性信息,如数据源源的连接数、用户名、密码
3,bean的依赖关系,Spring根据依赖关系配置完成Bean之间的装配
4,bean的行为配置,如生命周期范围及生命周期各过程的回调函数
bean元数据在spring容器中是有一一对应的BeanDefinition形成的Bean注册表
1,Spring1.0仅支持xml配置
2,Spring2.0新增基于注解配置的支持
3,Spring3.0新增基于java类配置的支持
4, Spring4.0新增基于Groovy动态语言配置支持
1,Spring1.0仅支持xml配置
2,Spring2.0新增基于注解配置的支持
3,Spring3.0新增基于java类配置的支持
4, Spring4.0新增基于Groovy动态语言配置支持
基于xml的配置
5.2 Bean基本配置
5.2.1 装配一个Bean
<bean id="foo" class="com.smart.foo" />
id为这个Bean的名称
id为这个Bean的名称
5.2.2 Bean的命名
bean的id是唯一的
bean的name属性可以是多个用“,”隔开<bean name="#car1,123,$car" />
如果存在多个name相同的bean,则最后声明的bean将被返回,因为后面的bean覆盖了前面同名的bean。
如果id和name都没有指定,<bean class = "com.baobaotao.simple.Car"/>,那么可以通过getBean("com.baobaotao.simple.Car)获取bean
如果存在多个实现类相同的匿名bean
<bean class="com.baobaotao.simple.Car">
<bean class="com.baobaotao.simple.Car">
<bean class="com.baobaotao.simple.Car">
第一个通过getBean("com.baobaotao.simple.Car")获得,第二个通过getBean("com.baobaotao.simple.Car#1")获得,第三个通过getBean("com.baobaotao.simple.Car#2")获得
bean的name属性可以是多个用“,”隔开<bean name="#car1,123,$car" />
如果存在多个name相同的bean,则最后声明的bean将被返回,因为后面的bean覆盖了前面同名的bean。
如果id和name都没有指定,<bean class = "com.baobaotao.simple.Car"/>,那么可以通过getBean("com.baobaotao.simple.Car)获取bean
如果存在多个实现类相同的匿名bean
<bean class="com.baobaotao.simple.Car">
<bean class="com.baobaotao.simple.Car">
<bean class="com.baobaotao.simple.Car">
第一个通过getBean("com.baobaotao.simple.Car")获得,第二个通过getBean("com.baobaotao.simple.Car#1")获得,第三个通过getBean("com.baobaotao.simple.Car#2")获得
5.3 依赖注入
5.3.1 属性注入
<property name="maxSpeed"><value>200</value></property>
xxx的属性名对应setXxx()方法
xxx的属性名对应setXxx()方法
javaBean要求“变量的前两个字母要么全部大写,要么全部小写”
5.3.2 构造函数注入
按类型匹配入参:
<constructor-arg type="java.lang.String">
<constructor-arg type="java.lang.String">
按索引匹配入参:
<constructor-arg index="0">
<constructor-arg index="0">
联合使用类型和索引匹配入参:
<constructor-arg index="0" type="java.lang.String">
<constructor-arg index="0" type="java.lang.String">
通过自身类型反射匹配入参:
<constructor-arg>
<ref bean="car">
</constructor-arg>
<constructor-arg>
<ref bean="car">
</constructor-arg>
循环依赖问题:
car构造依赖boss
boss构造依赖car
spring启动时,无法启动,只要将构造函数注入调整为属性注入就可以
car构造依赖boss
boss构造依赖car
spring启动时,无法启动,只要将构造函数注入调整为属性注入就可以
5.3.3 工厂方法注入
非静态工方法:
<bean id="carFactory" class="me.leifgao.bean.CarFactory"/>
<bean id="car5" factory-bean="carFactory" factory-method="createHongQiCar"/>
静态工方法:
<bean id="car5" class="me.leifgao.bean.CarFactory" factory-method="createHongQiCar"/>
5.3.4 选择注入方式的考量
5.4 注入参数详解
5.4.1 字面值
“字面值”:一般是指可用字符串表示的值,这些值可以通过<value>元素标签进行注入
spring提供了编辑器,可以将以字符串表示的字面值转化为内部变量的相对应类型
xml特殊实体符号:
<:< >:> &:& ":" ':'
当遇到这些特殊符号时有两种处理方式:
1,![CDATA[红旗&ca]] (也就是![CDATA[...]])
2,红旗&ca
[<] : [<]
[>] : [>]
[&] : [&]
["] : ["]
['] : [']
<:< >:> &:& ":" ':'
当遇到这些特殊符号时有两种处理方式:
1,![CDATA[红旗&ca]] (也就是![CDATA[...]])
2,红旗&ca
[<] : [<]
[>] : [>]
[&] : [&]
["] : ["]
['] : [']
spring不会忽略value标签中的空格符号
5.4.2 引用其他Bean
<ref>元素可以通过三个属性引用容器中的其他Bean:
1,bean:引用同一容器或父容器的Bean
2,local:只能引用同一配置文件中定义的Bean
3,parent:引用父容器中的Bean
1,bean:引用同一容器或父容器的Bean
2,local:只能引用同一配置文件中定义的Bean
3,parent:引用父容器中的Bean
5.4.3 内部Bean
如果一个bean只被另一个Bean引用而不会被容器中的任何其它Bean引用,则可以以内部Bean的方式注入到另一个Bean中:
<bean id = "boss" class="com.baobaotao.attr.Boss">
<property name = "car">
<bean class = "com.baobaotao.attr.Car">
<property name="maxSpeed" value="200"/>
<property name="price" value="20000.00"/>
</bean>
</property>
</bean>
则内部Car Bean不能被其他Bean引用,即使提供了id、name、scope属性
<bean id = "boss" class="com.baobaotao.attr.Boss">
<property name = "car">
<bean class = "com.baobaotao.attr.Car">
<property name="maxSpeed" value="200"/>
<property name="price" value="20000.00"/>
</bean>
</property>
</bean>
则内部Car Bean不能被其他Bean引用,即使提供了id、name、scope属性
5.4.4 null值
<bean id="car" class="com.baobaotao.attr.Car">
<property name="brand"><value></value></property>
</bean>
spring会解析成空字符串
<property name="brand"><null/></property>
spring会解析成null
<property name="brand"><value></value></property>
</bean>
spring会解析成空字符串
<property name="brand"><null/></property>
spring会解析成null
5.4.5 级联属性配置
级联属性配置:
<bean id="boss" class="com.baobaotao.arrt.Boos">
<property name="car.brand" value="吉利CT50"/>
</bean>
在spring3.0以前,上述配置,需要在boos类中显示实例化
private Car car = new Car();
在spring3.0以后,则无需配置,spring会自动为内置属性实例化一个对象
<bean id="boss" class="com.baobaotao.arrt.Boos">
<property name="car.brand" value="吉利CT50"/>
</bean>
在spring3.0以前,上述配置,需要在boos类中显示实例化
private Car car = new Car();
在spring3.0以后,则无需配置,spring会自动为内置属性实例化一个对象
5.4.6 集合类型属性
Set:
<bean id="boss" class="com.baobaotao.attr.Boss">
<property name="favorites">
<set>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</set>
</property>
</bean>
public class Boss{
private List favorites = new ArrayList();
get(),set()
}
List:
<bean id="boss" class="com.baobaotao.attr.Boss">
<property name="favorites">
<list>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</list>
</property>
</bean>
List属性可以通过<value>注入字符串,也可以通过<ref>注入容器中的其他的Bean
private List favorites = new ArrayList();
get(),set()
}
List:
<bean id="boss" class="com.baobaotao.attr.Boss">
<property name="favorites">
<list>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</list>
</property>
</bean>
List属性可以通过<value>注入字符串,也可以通过<ref>注入容器中的其他的Bean
Set:
<bean id="boss" class="com.baobaotao.attr.Boss">
<property name="favorites">
<set>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</set>
</property>
</bean>
Map:
public class Boss{
private Map jobs = new HashMap();
set();get();
}
<bean id="boss" class="com.baobaotao.attr.Boss">
<property name="jobs">
<map>
<entry>
<key><value>AM</value></key>
<value>会见客户</value>
</entry>
<entry>
<key><value>PM</value></key>
<value>公司内部会议</value>
</entry>
</map>
</property>
</bean>
public class Boss{
private Map jobs = new HashMap();
set();get();
}
<bean id="boss" class="com.baobaotao.attr.Boss">
<property name="jobs">
<map>
<entry>
<key><value>AM</value></key>
<value>会见客户</value>
</entry>
<entry>
<key><value>PM</value></key>
<value>公司内部会议</value>
</entry>
</map>
</property>
</bean>
Properties:
<bean id="boss" class="com.baobaotao.attr.Boss">
<property name="favorites">
<props>
<prop key="jobMail">leif@vipshop.com</prop>
<prop key="lifeMail">leif@gmail.com</prop>
</set>
</property>
</bean>
<bean id="boss" class="com.baobaotao.attr.Boss">
<property name="favorites">
<props>
<prop key="jobMail">leif@vipshop.com</prop>
<prop key="lifeMail">leif@gmail.com</prop>
</set>
</property>
</bean>
强类型集合:
private Map<String, Integer> jobTime = new HashMap<String, Integer>();
强类型的集合配置和普通的一样,但spring会自动转换类型
private Map<String, Integer> jobTime = new HashMap<String, Integer>();
强类型的集合配置和普通的一样,但spring会自动转换类型
集合合并:
<bean id="parentBoss" abstract="true" class="com.baobaotao.attr.Boss">
<property name="favorites">
<set>
<value>爬山</value>
<value>旅游</value>
</set>
</property>
<bean>
<bean id="childBoss" parent="parentBoss" class="com.baobaotao.attr.Boss">
<property name="favorites">
<set merge="true">
<value>爬山</value>
<value>旅游</value>
</set>
</property>
<bean>
最终childBoss将拥有5个元素
<bean id="parentBoss" abstract="true" class="com.baobaotao.attr.Boss">
<property name="favorites">
<set>
<value>爬山</value>
<value>旅游</value>
</set>
</property>
<bean>
<bean id="childBoss" parent="parentBoss" class="com.baobaotao.attr.Boss">
<property name="favorites">
<set merge="true">
<value>爬山</value>
<value>旅游</value>
</set>
</property>
<bean>
最终childBoss将拥有5个元素
通过util命名空间配置集合类型的Bean:
List类型的Bean:
<util:list id="favoriteList" list-class="java.util.LinkedList">
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</util:list>
Set类型的Bean:
<util:set id="favoriteList">
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</util:set>
Map类型的Bean:
<util:map id="emails">
<entry key="AM" value="会见客户"/>
<entry key="PM" value="公司内部会议"/>
</util:map>
<util:list> <util:set>还支持value-type属性,指定类型
<util:map> 支持key-type和value-type属性
List类型的Bean:
<util:list id="favoriteList" list-class="java.util.LinkedList">
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</util:list>
Set类型的Bean:
<util:set id="favoriteList">
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</util:set>
Map类型的Bean:
<util:map id="emails">
<entry key="AM" value="会见客户"/>
<entry key="PM" value="公司内部会议"/>
</util:map>
<util:list> <util:set>还支持value-type属性,指定类型
<util:map> 支持key-type和value-type属性
5.4.7 简化配置方式
使用P命名空间:
p:<属性名>="xxx"
p:<属性名>-ref="xxx"
p:<属性名>="xxx"
p:<属性名>-ref="xxx"
5.4.8 自动装配
autowire="<自动装配的类型>"
byName: 根据名称自动匹配。spring将容器中名字为car的Bean装配到Boss中的名为car的属性。
byType: 根据类型自动匹配。spring将容器中Car类型的Bean装配到Boss中的Car类型的属性中。
constructor: 与ByType类似,如果Boss有一个构造函数,该函数有一个Car类型的入参,spring自动将容器中Car类型的Bean作为入参,如果没有找到,则报错。
autodetect: 如果Bean提供了默认的构造函数,则采用byType;否则采用constructor。
byName: 根据名称自动匹配。spring将容器中名字为car的Bean装配到Boss中的名为car的属性。
byType: 根据类型自动匹配。spring将容器中Car类型的Bean装配到Boss中的Car类型的属性中。
constructor: 与ByType类似,如果Boss有一个构造函数,该函数有一个Car类型的入参,spring自动将容器中Car类型的Bean作为入参,如果没有找到,则报错。
autodetect: 如果Bean提供了默认的构造函数,则采用byType;否则采用constructor。
<beans>元素中的 default-autowire 属性可以配置全局的自动匹配,默认值为no。
基于注解的配置默认采用byType自动装配策略
5.5 方法注入
5.5.1 lookup方法注入
5.5.2 方法替换
pulic class Boss1{
public Car getCar(){
Car car = new Car();
car.setBrand("宝马Z4");
return car;
}
}
public class Boss2 implements MethodReplacer{
public Object reimplement(Object arg0, Method arg1, Object[] arg2) {
Car car = new Car();
car.setBrand("美人豹");
return car;
}
}
<bean id="boss1" class="com.baobaotao.bean.Boss1">
<replaced-method name="getCar" replacer="boss2"/>
</bean>
<bean id="boss2" class="com.baobaotao.bean.Boss2"/>
用于替换他人的Bean必须实现MethodReplacer接口,Spring将利用该接口方法去替换目标Bean的方法
public Car getCar(){
Car car = new Car();
car.setBrand("宝马Z4");
return car;
}
}
public class Boss2 implements MethodReplacer{
public Object reimplement(Object arg0, Method arg1, Object[] arg2) {
Car car = new Car();
car.setBrand("美人豹");
return car;
}
}
<bean id="boss1" class="com.baobaotao.bean.Boss1">
<replaced-method name="getCar" replacer="boss2"/>
</bean>
<bean id="boss2" class="com.baobaotao.bean.Boss2"/>
用于替换他人的Bean必须实现MethodReplacer接口,Spring将利用该接口方法去替换目标Bean的方法
5.6 <bean>之间的关系
5.6.1 继承
<bean id="abstractCar" class="com.baobaotao.tagdepend.Car"
p:brand="奥迪" p:price="2000.00" p:color="黑色" abstract="true"/>
<bean id ="car3" p:color="红色" parent="abstractCar/">
<bean id ="car4" p:color="白色" parent="abstractCar/">
父Bean申明了 abstract="true" 表示这个bean不能被实例化
p:brand="奥迪" p:price="2000.00" p:color="黑色" abstract="true"/>
<bean id ="car3" p:color="红色" parent="abstractCar/">
<bean id ="car4" p:color="白色" parent="abstractCar/">
父Bean申明了 abstract="true" 表示这个bean不能被实例化
5.6.2 依赖
<bean id="manager" class="com.baobaotao.tagdepend.CacheManager" depends-on="sysInit" />
<bean id="sysInit" class="com.baobaotao.tagdepend.SysInit" />
这样可以保证manager类被实例化前, sysInit会先被实例化
<bean id="sysInit" class="com.baobaotao.tagdepend.SysInit" />
这样可以保证manager类被实例化前, sysInit会先被实例化
5.6.3 引用
<bean id="car" class="com.baobaotao.tagdepend.Car" />
<bean id="boss" class="com.baobaotao.tagdepend.Boss">
<property name="carId">
<idref bean="car" />
</property>
</bean>
通过这样的配置,spring在启动时会检查引用的正确性
<bean id="boss" class="com.baobaotao.tagdepend.Boss">
<property name="carId">
<idref bean="car" />
</property>
</bean>
通过这样的配置,spring在启动时会检查引用的正确性
5.7 整合多个配置文件
<import resource="classpath:com/babatao/impl/beans1.xml">
5.8 Bean作用域
5.8.1 singleton作用域
任何通过容器的getBean("car")方法返回的实例都指向同一个Bean
如不不希望容器启动时提前实例化singleton的bean,可以通过lazy-init进行控制
<bean id="boss1" class="com.babaotao.scope.Boss" p:car-ref="car" lazy-init="true" />
如果该Bean被其他需要提前实例化的Bean引用到,Spring将忽略延迟实例化的设置
<bean id="boss1" class="com.babaotao.scope.Boss" p:car-ref="car" lazy-init="true" />
如果该Bean被其他需要提前实例化的Bean引用到,Spring将忽略延迟实例化的设置
5.8.2 prototype作用域
默认情况下,spring容器在启动时不实例化prototype的bean。spring容器将prototype的Bean交给调用者后,就不在管理它的生命周期了。
5.8.3 web应用环境相关的作用域
需要在web容器中进行额外的配置
servlet2.3之前:
<web-app>
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFileter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
高版本的web容器中:
<web-app>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
</web-app>
servlet2.3之前:
<web-app>
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFileter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
高版本的web容器中:
<web-app>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
</web-app>
request作用域:
<bean name="car" class="com.baobaotao.scope.Car" scope="request" />
每次HTTP请求调用到car Bean时,容器创建一个新的car bean,请求处理完毕,销毁这个Bean
<bean name="car" class="com.baobaotao.scope.Car" scope="request" />
每次HTTP请求调用到car Bean时,容器创建一个新的car bean,请求处理完毕,销毁这个Bean
session作用域:
<bean name="car" class="com.baobaotao.scope.Car" scope="session" />
car bean 作用域横跨整个HTTP session, session 中的所有HTTP请求都共享一个car bean, 当HTTP Session 结束后,实例被销毁。
<bean name="car" class="com.baobaotao.scope.Car" scope="session" />
car bean 作用域横跨整个HTTP session, session 中的所有HTTP请求都共享一个car bean, 当HTTP Session 结束后,实例被销毁。
5.8.4 作用域依赖问题
如果将Web相关的作用域的Bean注入到singleton或prototype的Bean中,需要一些额外的配置,才可以生效
<bean name="car" class="com.baobaotao.scope.Car" scope="request">
<aop:scoped-proxy/>
</bean>
<bean id="boss" class="com.baobaotao.scope.Boss">
<property name="car" ref="car" />
</bean>
当boss bean在web环境下,调用car bean时,spring aop 将启用动态代理判断boss bean位于哪个HTTP请求线程中,并从对应的HTTP请求线程中获取对应的car bean
<aop:scoped-proxy/>
</bean>
<bean id="boss" class="com.baobaotao.scope.Boss">
<property name="car" ref="car" />
</bean>
当boss bean在web环境下,调用car bean时,spring aop 将启用动态代理判断boss bean位于哪个HTTP请求线程中,并从对应的HTTP请求线程中获取对应的car bean
session作用域:
<bean name="car" class="com.baobaotao.scope.Car" scope="session" />
car bean 作用域横跨整个HTTP session, session 中的所有HTTP请求都共享一个car bean, 当HTTP Session 结束后,实例被销毁。
<bean name="car" class="com.baobaotao.scope.Car" scope="session" />
car bean 作用域横跨整个HTTP session, session 中的所有HTTP请求都共享一个car bean, 当HTTP Session 结束后,实例被销毁。
5.9 FactoryBean
FactoryBean 包含三个接口
T getObject(): 返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中的单实例缓存池中;
boolean isSingleton():确定由FactoryBean创建的Bean的作用域是singleton还是prototype
Class<?> getObjectType():返回FactoryBean创建Bean的类型
T getObject(): 返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中的单实例缓存池中;
boolean isSingleton():确定由FactoryBean创建的Bean的作用域是singleton还是prototype
Class<?> getObjectType():返回FactoryBean创建Bean的类型
当getBean("car")时,相当于调用CarFactoryBean#getObject()返回对象。
如果用户希望获取CarFactoryBean自身的实例,则getBean("&car")
如果用户希望获取CarFactoryBean自身的实例,则getBean("&car")
5.10 基于注解的配置
5.10.1 使用注解定义Bean
@Component("userDao")
public class UserDao {
}
相当于在xml配置文件中
<bean id="userDao" class="com.baobatao.anno.UserDao"/>
public class UserDao {
}
相当于在xml配置文件中
<bean id="userDao" class="com.baobatao.anno.UserDao"/>
@Repository: 用于对DAO实现类进行标注
@Service: 用于对Service实现类进行标注
@Controller: 用于对Controller实现类进行标注
在@Conmponent之外提供这三个特殊注解,是为了赋予一些特殊的功能
@Service: 用于对Service实现类进行标注
@Controller: 用于对Controller实现类进行标注
在@Conmponent之外提供这三个特殊注解,是为了赋予一些特殊的功能
5.10.2 使用注解配置信息启动Spring容器
spring的context的命名空间,提供了扫描类包的功能
<context:component-scan base-package="com.baobaotao" resource-pattern="anno/*.class">
则此时,Spring会扫描com.baobaotao包下面,anno包中的所有类
则此时,Spring会扫描com.baobaotao包下面,anno包中的所有类
<context:component-scan base-package="com.baobaotao">
<context:include-filter type="regex" expressionn="com\.baobaotao\.anno.*" />
<context:exclude-filter type="aspectj" expression="com.baobaotao..*Controller+" />
</context:component-scan>
<context:include-filter>表示要包含的目标类
<context:exclude-filter>表示要排除在外的项目
一个<context:component-scan>下可以拥有若干个<context:exclude-filter>和<context:include-filter>
<context:include-filter type="regex" expressionn="com\.baobaotao\.anno.*" />
<context:exclude-filter type="aspectj" expression="com.baobaotao..*Controller+" />
</context:component-scan>
<context:include-filter>表示要包含的目标类
<context:exclude-filter>表示要排除在外的项目
一个<context:component-scan>下可以拥有若干个<context:exclude-filter>和<context:include-filter>
类别 示例 说明
annotation com.baobaotao.XxxAnnotation 所有标注了XxxAnnotation的类。
assignable com.baobaotao.XxxService 所有继承或扩展XxxService的类。
aspectj com.baobaotao..*Service+ 所有类名以Service结束的类及继承或扩 展他们的类
regex com\.baobaotao\.anno\..* 所有com.baobaotao.anno类包下的 类。该类型采用正则表达式过滤
custom com.baobaotao.XxxTypeFilter 采用XxxTypeFile 通过代码的方式根据 过滤规则。该类必须实现org.springframework.core.type.TypeFilter接口
annotation com.baobaotao.XxxAnnotation 所有标注了XxxAnnotation的类。
assignable com.baobaotao.XxxService 所有继承或扩展XxxService的类。
aspectj com.baobaotao..*Service+ 所有类名以Service结束的类及继承或扩 展他们的类
regex com\.baobaotao\.anno\..* 所有com.baobaotao.anno类包下的 类。该类型采用正则表达式过滤
custom com.baobaotao.XxxTypeFilter 采用XxxTypeFile 通过代码的方式根据 过滤规则。该类必须实现org.springframework.core.type.TypeFilter接口
5.10.3 自动装配Bean
使用@Autowired进行自动注入
@Autowired默认按类型匹配的方式自动注入,在容器中查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入到@Autowired标注的变量中
@Autowired默认按类型匹配的方式自动注入,在容器中查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入到@Autowired标注的变量中
使用@Autowired的required属性
如果容器中没有一个和标注变量类型匹配的Bean,Spring容器启动将报NoSuchBeanDefinitionException的异常。如果希望即使没匹配也不报错,则可以使用@Autowired(required=false)进行标注
如果容器中没有一个和标注变量类型匹配的Bean,Spring容器启动将报NoSuchBeanDefinitionException的异常。如果希望即使没匹配也不报错,则可以使用@Autowired(required=false)进行标注
@Qualifier指定注入Bean的名称
如果容器中有多个Bean匹配时,可以通过@Qualifier注解限定Bean的名称。
@Qualifier("userDao")
private UserDao userDao;
如果容器中有多个Bean匹配时,可以通过@Qualifier注解限定Bean的名称。
@Qualifier("userDao")
private UserDao userDao;
对类方法进行标注
自动将LogDao传给方法入参:
@Autowired
public void setLogDao(LogDao logDao){
this.logDao = logDao
}
自动将名为userDao的Bean传给方法入参
@Autowired
@Qualifier("userDao")
public void setUserDao(UserDao userDao){
this.userDao = userDao
}
自动将LogDao传给方法入参:
@Autowired
public void setLogDao(LogDao logDao){
this.logDao = logDao
}
自动将名为userDao的Bean传给方法入参
@Autowired
@Qualifier("userDao")
public void setUserDao(UserDao userDao){
this.userDao = userDao
}
如果方法有多个入参,默认情况下,Spring自动选择匹配入参类型的Bean进行注入。也允许对入参标注@Qualifier以指定Bean的名称。
@Autowired
public void init(Qualifier("userDao")UserDao userDao, LogDao logDao){
....
}
@Autowired
public void init(Qualifier("userDao")UserDao userDao, LogDao logDao){
....
}
对集合类进行标注
如果对类中的集合类变量或方法中的集合类入参进行@Autowired标注,Spring会将容器中类型匹配的Bean都自动注入进来。
@Autowired
private List<Plugin> plugins;
@Autowired
private Map<String, Plugin> pluginMaps;(将所有的Plugin装入到map中,key为bean名字,value为实例,spring4.0支持)
如果对类中的集合类变量或方法中的集合类入参进行@Autowired标注,Spring会将容器中类型匹配的Bean都自动注入进来。
@Autowired
private List<Plugin> plugins;
@Autowired
private Map<String, Plugin> pluginMaps;(将所有的Plugin装入到map中,key为bean名字,value为实例,spring4.0支持)
在bean上标注 @Lazy ,然后再注入的地方标注 @Lazy和@Repository,则延迟到调用此属性的时候才会注入值
@Resource
private void setCar(Car car){
.....
}
如果@Resource未指定"car"属性,则会根据属性方法得到需要注入bean的名称。@Resource是按照名称进行注入的
@Inject和@Autowired一样,也是按照类型匹配注入Bean的,但是没有required属性。
private void setCar(Car car){
.....
}
如果@Resource未指定"car"属性,则会根据属性方法得到需要注入bean的名称。@Resource是按照名称进行注入的
@Inject和@Autowired一样,也是按照类型匹配注入Bean的,但是没有required属性。
5.10.4 Bean作用范围及生命过程方法
@Scope("prototype")指定Bean的作用范围
@PostConstruct和@PreDestroy注解,可以定义多个,这两个是JSR规范,不需要继承spring的类,
在spring中是 InitDestroyAnnotationBeanPostProcessor来处理的
在spring中是 InitDestroyAnnotationBeanPostProcessor来处理的
@Qualifier指定注入Bean的名称
如果容器中有多个Bean匹配时,可以通过@Qualifier注解限定Bean的名称。
@Qualifier("userDao")
private UserDao userDao;
如果容器中有多个Bean匹配时,可以通过@Qualifier注解限定Bean的名称。
@Qualifier("userDao")
private UserDao userDao;
5.11 基于java类的配置
5.11.1 使用java类提供Bean定义信息
@Configuration
public class AppConf{
@Bean
public UserDao userDao {
return new UserDao();
}
}
@Configuration注解,说明这个类可用于提供Bean的定义信息
@Bean的类方法相当于提供了一个Bean的定义信息
Bean的类型由方法名返回值类型决定,名称默认和方法名相同。也可以通过入参显示指定Bean名称,如
@Bean(name="userDao")
public class AppConf{
@Bean
public UserDao userDao {
return new UserDao();
}
}
@Configuration注解,说明这个类可用于提供Bean的定义信息
@Bean的类方法相当于提供了一个Bean的定义信息
Bean的类型由方法名返回值类型决定,名称默认和方法名相同。也可以通过入参显示指定Bean名称,如
@Bean(name="userDao")
@Configuration注解本身已经标注了@Component注解,所以标注了@Configuration的类,可以像普通的Bean一样被注入到其他Bean中。
调用标注了@Bean注解的方法时,并不是只是简单的调用方法,spring会对这些方法进行改造(AOP增强),所以调用这些@Bean标注的方法时,是从容器中返回相应的Bean。
在@Bean处,还可以标注@Scope("prototype")注解
调用标注了@Bean注解的方法时,并不是只是简单的调用方法,spring会对这些方法进行改造(AOP增强),所以调用这些@Bean标注的方法时,是从容器中返回相应的Bean。
在@Bean处,还可以标注@Scope("prototype")注解
5.11.2 使用基于Java类的配置信息启动Spring容器
直接通过@Configuration类启动Spring容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConf.class)
直接使用AppConf类的配置信息启动Spring容器。
还支持加载多个@Configuration配置类,但是必须要刷新。
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(DaoConfig.class);
ctx.register(ServiceConfig.class);
ctx.refresh();
也可以通过@Import将多个配置类组装到一起
@Configuration
@Import(DaoConfig.class)
public class ServiceConfig{
}
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConf.class)
直接使用AppConf类的配置信息启动Spring容器。
还支持加载多个@Configuration配置类,但是必须要刷新。
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(DaoConfig.class);
ctx.register(ServiceConfig.class);
ctx.refresh();
也可以通过@Import将多个配置类组装到一起
@Configuration
@Import(DaoConfig.class)
public class ServiceConfig{
}
通过XML配置文件引用@Configuration的配置
因为@Configuration的注解本身相当于一个标注了@Component的类,所以可以被<context:component-sacn>扫包扫到就行
<context : component-scan base-package="..." resource-pattern="AppConf.class">
因为@Configuration的注解本身相当于一个标注了@Component的类,所以可以被<context:component-sacn>扫包扫到就行
<context : component-scan base-package="..." resource-pattern="AppConf.class">
通过Configuration配置类引用XML配置信息
假设app.xml配置文件中定义了两个类,@Configuration的类想用这两个类
在@Configuration配置类中标注@ImportResource
@Configuration
@ImportResource("classpath:com/baobaotao/conf/beans3.xml")
public class LogonAppConfig{
}
假设app.xml配置文件中定义了两个类,@Configuration的类想用这两个类
在@Configuration配置类中标注@ImportResource
@Configuration
@ImportResource("classpath:com/baobaotao/conf/beans3.xml")
public class LogonAppConfig{
}
5.12 基于Groovy DSL的配置
5.13 通过编码方式动态添加Bean
5.13.1 通过DefaultListableBeanFactory
DefaultListableBeanFactory可以实现Bean动态注入
在实现了BeanFactoryPostProcessor的类中,调用DefaultListableBeanFactory即可,
第一种:
在实现了BeanFactoryPostProcessor的类中,调用DefaultListableBeanFactory即可,
第一种:
//①将ConfigurableListableBeanFactory转化为DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) bf;
//②通过BeanDefinitionBuilder创建Bean定义
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.genericBeanDefinition(UserService.class);
//③设置属性userDao,此属性引用已经定义的bean:userDao
bdb.addPropertyReference("userDao","userDao");
//④注册Bean定义
beanFactory.registerBeanDefinition("userService1", bdb.getRawBeanDefinition()); 第二种: bf2.registerSingleton(beanName, new UserService());
@Configuration注解本身已经标注了@Component注解,所以标注了@Configuration的类,可以像普通的Bean一样被注入到其他Bean中。
调用标注了@Bean注解的方法时,并不是只是简单的调用方法,spring会对这些方法进行改造(AOP增强),所以调用这些@Bean标注的方法时,是从容器中返回相应的Bean。
在@Bean处,还可以标注@Scope("prototype")注解
调用标注了@Bean注解的方法时,并不是只是简单的调用方法,spring会对这些方法进行改造(AOP增强),所以调用这些@Bean标注的方法时,是从容器中返回相应的Bean。
在@Bean处,还可以标注@Scope("prototype")注解
5.13.2 扩展自定义标签
1,采用XSD描述自定义标签的元素属性
就是编写自定义xml的shema内容
就是编写自定义xml的shema内容
2,编写服务标签解析类
需要实现 BeanDefinitionParser#parse()
需要实现 BeanDefinitionParser#parse()
3,注册Spring命名空间解析器
需要实现NamespaceHandlerSupport#init()
需要实现NamespaceHandlerSupport#init()
4,告诉Spring自定义标签的文档结构及解析它的类
在源码resources目录创建META-INF文件夹,创建spring.handlers和spring.schemas两个文件
spring.schemas :
http\://www.smart.com.schema/service.xds=com/smart/schema/userservice.xsd
spring.handlers:
http\://www.smart.com/schema/service=com.smart.dynamic.UserServiceNamespaceHandler
在源码resources目录创建META-INF文件夹,创建spring.handlers和spring.schemas两个文件
spring.schemas :
http\://www.smart.com.schema/service.xds=com/smart/schema/userservice.xsd
spring.handlers:
http\://www.smart.com/schema/service=com.smart.dynamic.UserServiceNamespaceHandler
6 Spring容器高级主题
6.1 Spring容器的技术内幕
6.1.1 内部工作机制
AbstractApplicationContext是ApplicationContext的抽象实现类,该类的refresh()方法展示了加载配置文件后的各项处理过程
1,ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
初始化BeanFactory:根据配置文件实例化BeanFactory,在obtainFreshBeanFactory()方法中,首先调用refreshBeanFactory()方法刷新BeanFactory,然后调用getBeanFactory()方法获取BeanFactory,spring会将配置文件信息装入到Bean定义注册表(BeanDefinitionRegistry)中,但此时Bean还没有初始化。
2,invokeBeanFactoryPostProcessors()
调用工厂后处理器:根据反射从BeanDefinitionRegistry中找出所有BeanFactoryPostProcessor类型的Bean,并调用postProcessBeanFactory()接口方法;
3,registerBeanPostProcessors()
注册Bean后处理器:根据反射机制从BeanDefinitionRegistry中找出所有BeanPostProcessor类型的Bean,并将它们注册到容器Bean后处理器的注册表中
4,initMessageSource()
初始化消息源:初始化容器的国际化信息资源
5,initApplicationEventMulticaster()
初始化应用上下文事件广播器
6,onRefresh()
初始化其它特殊的bean,这是个hook方法
7,registerListeners()
注册事件监听器
8,finishBeanFactoryInitialization(beanFactory)
初始化所有单实例的bean,使用懒初始化模式的bean除外,初始化bean后,将他们放入Spring容器的缓存中
9,finishRefresh();
发布上下文刷新事件,
1,ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
初始化BeanFactory:根据配置文件实例化BeanFactory,在obtainFreshBeanFactory()方法中,首先调用refreshBeanFactory()方法刷新BeanFactory,然后调用getBeanFactory()方法获取BeanFactory,spring会将配置文件信息装入到Bean定义注册表(BeanDefinitionRegistry)中,但此时Bean还没有初始化。
2,invokeBeanFactoryPostProcessors()
调用工厂后处理器:根据反射从BeanDefinitionRegistry中找出所有BeanFactoryPostProcessor类型的Bean,并调用postProcessBeanFactory()接口方法;
3,registerBeanPostProcessors()
注册Bean后处理器:根据反射机制从BeanDefinitionRegistry中找出所有BeanPostProcessor类型的Bean,并将它们注册到容器Bean后处理器的注册表中
4,initMessageSource()
初始化消息源:初始化容器的国际化信息资源
5,initApplicationEventMulticaster()
初始化应用上下文事件广播器
6,onRefresh()
初始化其它特殊的bean,这是个hook方法
7,registerListeners()
注册事件监听器
8,finishBeanFactoryInitialization(beanFactory)
初始化所有单实例的bean,使用懒初始化模式的bean除外,初始化bean后,将他们放入Spring容器的缓存中
9,finishRefresh();
发布上下文刷新事件,
6.1.2 BeanDefinition
RootBeanDefinition是最常用的实现类,配置文件中的父<bean>用RootBeanDefinition表示,子<bean>用
ChildBeanDefiniton表示,没有父<bean>的<bean>则用RootBeanDefinition表示。AbstractBeanDefinition对两者共同的类信息进行抽象
ChildBeanDefiniton表示,没有父<bean>的<bean>则用RootBeanDefinition表示。AbstractBeanDefinition对两者共同的类信息进行抽象
1,利用BeanDefinitionReader读取配置信息的Resource, 通过XML解析器解析成DOM对象,然后简单的生成BeanDefinition对象。
2,利用注册的BeanFactoryPostProcessor对半成品的BeanDefinition进行加工,将占位符表示的配置解析成最终的实际值
2,利用注册的BeanFactoryPostProcessor对半成品的BeanDefinition进行加工,将占位符表示的配置解析成最终的实际值
6.1.3 InstantiationStrategy
通过InstantiationStrategy负责根据BeanDefinition对象创建一个Bean实例。
SimpleInstantiationStrategy是最常用的实例化策略,该策略利用Bean实现类的默认构造函数。带参构造函数或工厂方法创建Bean的实例
CglibSubclassingInstantiationStrategy扩展了SimpleInstantiationStrategy,利用CGLib类库为Bean动态生成子类,在子类中生成方法注入的逻辑,然后利用这个子类创建Bean的实例
InstantiationStrategy仅负责实例化Bean的操作,不会参与Bean属性的设置工作。属性填充由BeanWrapper完成。
6.1.4 BeanWrapper
BeanWrapperImpl具有三个身份:
1, bean包裹器; 2,属性访问器;3,属性编辑器注册表
1, bean包裹器; 2,属性访问器;3,属性编辑器注册表
6.2 属性编辑器
6.2.1 JavaBean编辑器
PropertyEditor接口
Object getValue(): 返回属性当前值,基本类型被封装成对应的封装类实体
void setValue(Object newValue): 设置属性的值,基本类型一封装类传入
String getAsText(): 将属性对象用一个字符串表示,默认返回null,表示不能以字符串表示
void setAsTest(): 用一个字符串去更新属性的内部值,这个字符串一般从外部属性编辑器传入
String[] getTags(): 返回几个有效的候选项(如boolean 有 true,false),然后属性编辑器以下拉框的方式显示出来。
String getJavaInitializationString(): 为属性提供一个表示初始值的字符串
Object getValue(): 返回属性当前值,基本类型被封装成对应的封装类实体
void setValue(Object newValue): 设置属性的值,基本类型一封装类传入
String getAsText(): 将属性对象用一个字符串表示,默认返回null,表示不能以字符串表示
void setAsTest(): 用一个字符串去更新属性的内部值,这个字符串一般从外部属性编辑器传入
String[] getTags(): 返回几个有效的候选项(如boolean 有 true,false),然后属性编辑器以下拉框的方式显示出来。
String getJavaInitializationString(): 为属性提供一个表示初始值的字符串
BeanInfo
BeanInfo描述了JavaBean哪些属性可以编辑及对应的属性编辑器,每个属性对应一个属性描述其PropertyDescriptor。
PropertyDescriptor[] getPropertyDescriptors() : 返回JavaBean的属性描述器数组。
PropertyDescriptor
PropertyDescriptor(String propertyName, Class beanClass) : propertyName为属性名,beanClass为JavaBean对应的Class。
setPropertyEditorClass(Class propertyEditorClass) :为JavaBean的属性指定编辑器。
BeanInfo描述了JavaBean哪些属性可以编辑及对应的属性编辑器,每个属性对应一个属性描述其PropertyDescriptor。
PropertyDescriptor[] getPropertyDescriptors() : 返回JavaBean的属性描述器数组。
PropertyDescriptor
PropertyDescriptor(String propertyName, Class beanClass) : propertyName为属性名,beanClass为JavaBean对应的Class。
setPropertyEditorClass(Class propertyEditorClass) :为JavaBean的属性指定编辑器。
6.2.2 Spring默认属性编辑器
Spring在PropertyEditorRegistrySupport中为常见的属性类提供了默认的属性编辑器。
PropertyEditorRegistrySupport中,
defaultEditors: 保存默认属性类型的编辑器,defaultEditors = new HashMap<Class<?>, PropertyEditor>(64);
customEditors: 保存用户自定义的属性编辑器,customEditors = new HashMap<Class<?>, PropertyEditor>(64);
defaultEditors: 保存默认属性类型的编辑器,defaultEditors = new HashMap<Class<?>, PropertyEditor>(64);
customEditors: 保存用户自定义的属性编辑器,customEditors = new HashMap<Class<?>, PropertyEditor>(64);
6.2.3 自定义属性编辑器
在Boss类中配置Car类,有两种方法:
一,在配置文件中给car配置一个<bean>,然后再Boss的配置中通过ref引用car Bean。
二,给Car提供一个自定义的属性编辑器,然后通过字面值给Boss的car属性配置值。
一,在配置文件中给car配置一个<bean>,然后再Boss的配置中通过ref引用car Bean。
二,给Car提供一个自定义的属性编辑器,然后通过字面值给Boss的car属性配置值。
注册自定义的属性编辑器
如果用的是BeanFactory,则需要手工调用registerCustomEditor(Class requiredType, PropertyEditor pro
pertyEditor)
如果是Application,则可以在配置文件中通过CustomEditorConfigurer注册。CustomEditorConfigurer实现了BeanFactoryPostProcessor接口,所以是一个Bean工厂后处理器。
<bean class="org.springframework.beans.factory.confgi.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="com.smart.editor.Car" value = "com.smart.editor.CustomCarEditor" />
</entry>
</map>
</property>
</bean>
<bean id="boss" class="com.smart.editor.Boss">
<property name="name" value="john">
<property name="car" value="红旗,200,20000.00">
</bean>
如果用的是BeanFactory,则需要手工调用registerCustomEditor(Class requiredType, PropertyEditor pro
pertyEditor)
如果是Application,则可以在配置文件中通过CustomEditorConfigurer注册。CustomEditorConfigurer实现了BeanFactoryPostProcessor接口,所以是一个Bean工厂后处理器。
<bean class="org.springframework.beans.factory.confgi.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="com.smart.editor.Car" value = "com.smart.editor.CustomCarEditor" />
</entry>
</map>
</property>
</bean>
<bean id="boss" class="com.smart.editor.Boss">
<property name="name" value="john">
<property name="car" value="红旗,200,20000.00">
</bean>
6.3 使用外部属性文件
6.3.1 PropertyPlaceholderConfigurer属性文件
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p : location="classpath:com/smart/placeholder/jdbc.properties"
p : fileEncoding="utf-8" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p : driverClassName="${driverClassName}"
p : url="${url}"
p : username="$usernName"
p : password="${password}" />
p : location="classpath:com/smart/placeholder/jdbc.properties"
p : fileEncoding="utf-8" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p : driverClassName="${driverClassName}"
p : url="${url}"
p : username="$usernName"
p : password="${password}" />
PropertyPlaceholderConfigurer的其他属性:
locations : 一个属性文件,locations指定。多个属性文件,通过locations属性进行设置。像配置List一样配置locations属性。
fileEncoding : Spring默认使用操作系统的编码,其他编码需要指定
order : 如果配置了多个PropertyPlaceholderConfigurer,则通过该属性指定有限顺序
placeholderPrefix : "${"为默认的占位前缀符,可以更改
placeholderSuffix : "}"为默认的占位后缀,可以更改
locations : 一个属性文件,locations指定。多个属性文件,通过locations属性进行设置。像配置List一样配置locations属性。
fileEncoding : Spring默认使用操作系统的编码,其他编码需要指定
order : 如果配置了多个PropertyPlaceholderConfigurer,则通过该属性指定有限顺序
placeholderPrefix : "${"为默认的占位前缀符,可以更改
placeholderSuffix : "}"为默认的占位后缀,可以更改
也可以使用context命名空间定义属性文件,相比于PropertyPlaceholderConfigurer配置,这种方法更优
雅
<context : property-placeholder
location="classpath:com/smart/placeholder/jdbc.properties" />
雅
<context : property-placeholder
location="classpath:com/smart/placeholder/jdbc.properties" />
在XML文件中,使用${propName}引用属性值
在类中,使用@Value注解自动注入容器已有的属性
在类中,使用@Value注解自动注入容器已有的属性
6.3.2 使用加密的属性文件
PropertyResourceConfigurer类有以下几个方法
void convertProperties(Properties props) :
覆盖此方法,可以对所有的属性值进行转换处理
String convertProperty(String propertyName, String propertyValue) :
在加载属性文件并读取文件中的每个属性时,会调用此方法进行转换处理
String convertPropertyValue(String originalValue) :
和上面的方法类似,没有属性值形参
void convertProperties(Properties props) :
覆盖此方法,可以对所有的属性值进行转换处理
String convertProperty(String propertyName, String propertyValue) :
在加载属性文件并读取文件中的每个属性时,会调用此方法进行转换处理
String convertPropertyValue(String originalValue) :
和上面的方法类似,没有属性值形参
6.3.3 属性文件自身的引用
可以在jdbc.properties中引用其他定义的属性值
dbName=sampledb
url=jddbc:mysql://localhost:3306/${dbName}
dbName=sampledb
url=jddbc:mysql://localhost:3306/${dbName}
6.4 引用Bean的属性值
在Spring3.0中,可以通过#{beanName.beanProp}的方式引用另一个Bean的值
XML文件中, 直接使用#{beanName.beanProp}
类中,@Value("#{beanName.propName}")使用
类中,@Value("#{beanName.propName}")使用
6.5 国际化信息
6.6 容器事件
事件源 : 事件产生者
事件监听器注册表 : 保存事件监听器
事件广播器 : 负责把事件通知给事件监听器
事件监听器注册表 : 保存事件监听器
事件广播器 : 负责把事件通知给事件监听器
6.6.1 Spring事件类结构
事件类
ApplicationEvent#ApplicationEvent(Object source) :
通过source指定事件源
ApplicationContextEvent:容器事件,有四个子类
ContextClosedEvent : 容器关闭事件
ContextRefreshedEvent :容器刷新事件
ContextStartedEvent :容器开始事件
ContextStoppedEvent:容器停止事件
ApplicationEvent#ApplicationEvent(Object source) :
通过source指定事件源
ApplicationContextEvent:容器事件,有四个子类
ContextClosedEvent : 容器关闭事件
ContextRefreshedEvent :容器刷新事件
ContextStartedEvent :容器开始事件
ContextStoppedEvent:容器停止事件
事件监听器接口
ApplicationListener#onApplicationEvent(E event):
该方法接收ApplicationEvent事件对象,编写处理事件的代码
SmartApplicationListener接口Spring3.0新增的:
boolean supprotsEventType(Class<? extends ApplicationEvent> eventType) :
指定监听器支持哪种类型的容器事件
boolean supportsSourceType(Class<?> sourceType) :
指定监听器仅对何种事件源对象作出响应
GenericApplicationListener接口是Spring4.2新增的。
boolean supprotsEventType(ResolvableType eventType) :
指定支持的事件类型。
boolean supportsSourceType(Class<?> sourceType) :
指定监听器对何种事件源作出响应。
ApplicationListener#onApplicationEvent(E event):
该方法接收ApplicationEvent事件对象,编写处理事件的代码
SmartApplicationListener接口Spring3.0新增的:
boolean supprotsEventType(Class<? extends ApplicationEvent> eventType) :
指定监听器支持哪种类型的容器事件
boolean supportsSourceType(Class<?> sourceType) :
指定监听器仅对何种事件源对象作出响应
GenericApplicationListener接口是Spring4.2新增的。
boolean supprotsEventType(ResolvableType eventType) :
指定支持的事件类型。
boolean supportsSourceType(Class<?> sourceType) :
指定监听器对何种事件源作出响应。
事件广播器
ApplicationEventMulticaster
AbstractApplicationEventMulticaster
SimpleApplicationEventMulticaster
ApplicationEventMulticaster
AbstractApplicationEventMulticaster
SimpleApplicationEventMulticaster
6.6.2 解构Spring事件体系的具体实现
6.6.3 一个实例
7 Spring AOP基础
7.1 AOP概览
7.1.1 AOP到底是什么
7.1.2 AOP术语
1.连接点(Joinpoint)
连接点由两个信息确定:一是用方法表示的程序执行点;二是用相对位置表示的方位
连接点由两个信息确定:一是用方法表示的程序执行点;二是用相对位置表示的方位
2.切点(Pointcut)
通过类和方法作为条件,查询到连接点中的执行点(因为切点不包含方位信息)
通过类和方法作为条件,查询到连接点中的执行点(因为切点不包含方位信息)
3.增强(Advice)
由两个组成,一是一段代码,二是方位信息
由两个组成,一是一段代码,二是方位信息
4.目标对象(Target)
待增强织入的目标类
待增强织入的目标类
5.引介(Introduction)
一种特殊的增强,给类添加一些属性和方法。
一种特殊的增强,给类添加一些属性和方法。
6.织入(Weaving)
将增强添加到目标类的具体连接点的过程
AOP有三种织入方式
(1) 编译期织入,需要特殊的Java编译器
(2) 类装载织入,需要特殊的类装载器
(3) 动态代理,在运行期为目标类添加增强生成子类的方式。
Spring采用动态代理,AspectJ采(1)和(2)
将增强添加到目标类的具体连接点的过程
AOP有三种织入方式
(1) 编译期织入,需要特殊的Java编译器
(2) 类装载织入,需要特殊的类装载器
(3) 动态代理,在运行期为目标类添加增强生成子类的方式。
Spring采用动态代理,AspectJ采(1)和(2)
7.代理(Proxy)
一个类被AOP增强后,就产生了一个结果类,融合了原类和增强逻辑的代理类。
代理类既可以是和原类具有相同接口的类,也可能是原类的子类,所以才可以用和原类相同的方式调用
一个类被AOP增强后,就产生了一个结果类,融合了原类和增强逻辑的代理类。
代理类既可以是和原类具有相同接口的类,也可能是原类的子类,所以才可以用和原类相同的方式调用
8.切面(Aspect)
切面由切点和增强(引介)组成。
切面由切点和增强(引介)组成。
7.2 基础知识
7.2.1 带有横切逻辑的实例
PropertyEditor接口
Object getValue(): 返回属性当前值,基本类型被封装成对应的封装类实体
void setValue(Object newValue): 设置属性的值,基本类型一封装类传入
String getAsText(): 将属性对象用一个字符串表示,默认返回null,表示不能以字符串表示
void setAsTest(): 用一个字符串去更新属性的内部值,这个字符串一般从外部属性编辑器传入
String[] getTags(): 返回几个有效的候选项(如boolean 有 true,false),然后属性编辑器以下拉框的方式显示出来。
String getJavaInitializationString(): 为属性提供一个表示初始值的字符串
Object getValue(): 返回属性当前值,基本类型被封装成对应的封装类实体
void setValue(Object newValue): 设置属性的值,基本类型一封装类传入
String getAsText(): 将属性对象用一个字符串表示,默认返回null,表示不能以字符串表示
void setAsTest(): 用一个字符串去更新属性的内部值,这个字符串一般从外部属性编辑器传入
String[] getTags(): 返回几个有效的候选项(如boolean 有 true,false),然后属性编辑器以下拉框的方式显示出来。
String getJavaInitializationString(): 为属性提供一个表示初始值的字符串
BeanInfo
BeanInfo描述了JavaBean哪些属性可以编辑及对应的属性编辑器,每个属性对应一个属性描述其PropertyDescriptor。
PropertyDescriptor[] getPropertyDescriptors() : 返回JavaBean的属性描述器数组。
PropertyDescriptor
PropertyDescriptor(String propertyName, Class beanClass) : propertyName为属性名,beanClass为JavaBean对应的Class。
setPropertyEditorClass(Class propertyEditorClass) :为JavaBean的属性指定编辑器。
BeanInfo描述了JavaBean哪些属性可以编辑及对应的属性编辑器,每个属性对应一个属性描述其PropertyDescriptor。
PropertyDescriptor[] getPropertyDescriptors() : 返回JavaBean的属性描述器数组。
PropertyDescriptor
PropertyDescriptor(String propertyName, Class beanClass) : propertyName为属性名,beanClass为JavaBean对应的Class。
setPropertyEditorClass(Class propertyEditorClass) :为JavaBean的属性指定编辑器。
7.2.2 JDK动态代理
JDK动态代理,涉及到 Proxy和InvocationHandler
见springDemo项目代码
7.2.3 CGLib动态代理
使用JDK创建代理只能为接口创建实例。
见springDemo
7.2.4 AOP联盟
http://aopalliance.sourceforge.net
7.2.5 代理知识小结
7.3 创建增强类
Spring使用增强类定义横切逻辑
7.3.1 增强类型
前置增强:
org.springframmework.aop.BeforeAdvice代表前置增强
由于spring只支持方法级的增强,所以MethodBeforeAdvice是目前可用的前置增强
org.springframmework.aop.BeforeAdvice代表前置增强
由于spring只支持方法级的增强,所以MethodBeforeAdvice是目前可用的前置增强
后置增强:
org.springframmework.aop.AfterReturningAdvice代表后置增强,表示方法执行后实施增强
org.springframmework.aop.AfterReturningAdvice代表后置增强,表示方法执行后实施增强
环绕增强:
org.aopalliance.intercept.MethodInterceptor代表环绕增强,表示在目标方法执行前后实施增强
org.aopalliance.intercept.MethodInterceptor代表环绕增强,表示在目标方法执行前后实施增强
异常抛出增强:
org.springframework.aop.ThrowsAdvice代表抛出异常增强,表示在目标方法抛出异常后实施增强。
org.springframework.aop.ThrowsAdvice代表抛出异常增强,表示在目标方法抛出异常后实施增强。
引介增强:
org.springframework.aop.IntroductionInterceptor代表引介增强,表示在目标类中添加一些新的方法和属性
org.springframework.aop.IntroductionInterceptor代表引介增强,表示在目标类中添加一些新的方法和属性
7.3.2 前置增强
springDemo代码
Spring定义了org.springframework.aop.framework.AopProxy接口
Cglib2AopProxy使用Cglib动态代理技术
JdkDynamicAopProxy使用JDK动态代理技术
Cglib2AopProxy使用Cglib动态代理技术
JdkDynamicAopProxy使用JDK动态代理技术
如果使用了ProxyFactory#setInterfaces(Class[] interfaces),则使用使用JDK动态代理
如果是针对类的的代理,则使用Cglib2AopProxy
如果ProxyFactory#setOptimize(true),则针对接口的代理也是使用Cglib2AopProxy
如果是针对类的的代理,则使用Cglib2AopProxy
如果ProxyFactory#setOptimize(true),则针对接口的代理也是使用Cglib2AopProxy
ProxyFactory可以添加多个增强,调用顺序和添加顺序一致。
xml配置
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.smart.advice.Waiter"
p:interceptorNames="greetingAdvice"
p:target-ref="target" />
target : 代理类的目标对象
proxyInterfaces : 代理所要实现的接口,可以是多个接口
interceptorNames : 切面方法抽取出来的bean,这些bean必须实现org.aopalliance.MethodInterceptor
或org.springframework.aop.Advisor的bean,配置中的顺序对应调用的顺序。
singleton : 返回的单例是否是单实例,默认单实例
optimize : 当设置为true时,强制使用Cglib动态代理
proxyTargetClass : 是否对类进行代理。当设置为true时,使用Cglib动态代理
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.smart.advice.Waiter"
p:interceptorNames="greetingAdvice"
p:target-ref="target" />
target : 代理类的目标对象
proxyInterfaces : 代理所要实现的接口,可以是多个接口
interceptorNames : 切面方法抽取出来的bean,这些bean必须实现org.aopalliance.MethodInterceptor
或org.springframework.aop.Advisor的bean,配置中的顺序对应调用的顺序。
singleton : 返回的单例是否是单实例,默认单实例
optimize : 当设置为true时,强制使用Cglib动态代理
proxyTargetClass : 是否对类进行代理。当设置为true时,使用Cglib动态代理
7.3.3 后置增强
实现AfterReturningAdvice#afterReturning来定义后置增强的逻辑
最好使用<property name="interceptorNames">
<list>
<idref local="greetingBefore">
<idref local="greetingAfter">
</list>
</property>
<list>
<idref local="greetingBefore">
<idref local="greetingAfter">
</list>
</property>
7.3.4 环绕增强
实现MethodInterceptor#invoke()方法
会在target类的方法执行前后调用
会在target类的方法执行前后调用
7.3.5 异常抛出增强
实现ThrowsAdvice#afterThrowing()方法
必须采用
void afterThrowing(Method method, Object[] args, Object target, Throwable)
void afterThrowing(Method method, Object[] args, Object target, Throwable)
7.3.6 引介增强
7.4 创建切面
Spring通过org.springframework.aop.Pointcut接口描述切点
Poinccut由ClassFilter和MethodMatcher构成,通过ClassFilter定位到某些特定类上,通过MethodMatcher定位到某些特定方法上
Poinccut由ClassFilter和MethodMatcher构成,通过ClassFilter定位到某些特定类上,通过MethodMatcher定位到某些特定方法上
Spring支持两种方法匹配器 : 静态方法匹配器和动态方法匹配器
静态方法匹配器 : 仅对方法名签名(包括方法名和入参类型及顺序)进行匹配,静态匹配仅会匹配一次。
动态方法匹配器 : 在运行期检查入参的值,动态方法每次调用方法都会匹配。
静态方法匹配器 : 仅对方法名签名(包括方法名和入参类型及顺序)进行匹配,静态匹配仅会匹配一次。
动态方法匹配器 : 在运行期检查入参的值,动态方法每次调用方法都会匹配。
Spring支持两种方法匹配器 : 静态方法匹配器和动态方法匹配器
静态方法匹配器 : 仅对方法名签名(包括方法名和入参类型及顺序)进行匹配,静态匹配仅会匹配一次。
动态方法匹配器 : 在运行期检查入参的值,动态方法每次调用方法都会匹配。
静态方法匹配器 : 仅对方法名签名(包括方法名和入参类型及顺序)进行匹配,静态匹配仅会匹配一次。
动态方法匹配器 : 在运行期检查入参的值,动态方法每次调用方法都会匹配。
7.4.2 切面类型
增强既包含横切代码,又包含部分连接点信息,所以可以通过增强生成一个切面
但切点必须结合增强才能生成切面,应为切点不包含横切代码
但切点必须结合增强才能生成切面,应为切点不包含横切代码
切面可以分为3类:一般切面、切点切面、引介切面
Advisor:
代表一般切面,仅包含一个Advice,代表的横切的连接点是所有目标类的所有方法
PointcutAdvisor:包含Advice和Pointcut两个类。
IntroductionAdvisor : 应用于类层面上
Advisor:
代表一般切面,仅包含一个Advice,代表的横切的连接点是所有目标类的所有方法
PointcutAdvisor:包含Advice和Pointcut两个类。
IntroductionAdvisor : 应用于类层面上
PointcutAdvisor主要有6个具体的实现类
DefaultPointcutAdvisor:
通过任意Pointcut和Advice定义一个切面,不支持引介的切面类型
NameMatchMethodPointcutAdvisor:
按照方法名定义切点的切面
RegexpMethodPointcutAdvisor:
按照正则表达式匹配方法名进行切点定义的切面
StaticMethodMatcherPointcutAdvisor:
静态方法匹配器切点定义的切面
AspectJExpressionPointcutAdvisor:
用于AspectJ切点表达式定义切点的切面
AspectJPointcutAdvisor:
用于AspectJ语法定义切点的切面
DefaultPointcutAdvisor:
通过任意Pointcut和Advice定义一个切面,不支持引介的切面类型
NameMatchMethodPointcutAdvisor:
按照方法名定义切点的切面
RegexpMethodPointcutAdvisor:
按照正则表达式匹配方法名进行切点定义的切面
StaticMethodMatcherPointcutAdvisor:
静态方法匹配器切点定义的切面
AspectJExpressionPointcutAdvisor:
用于AspectJ切点表达式定义切点的切面
AspectJPointcutAdvisor:
用于AspectJ语法定义切点的切面
7.4.3 静态普通方法名匹配切面
springDemo代码
7.4.4 静态正则表达式方法匹配切面
RegexpMethodPointcutAdvisor是正则表达式方法匹配的切面实现类
pattern : 只能定义一个匹配模式串
patterns : 定义多个模式匹配串
advice : 定义增强
order : 切面在织入时对应的顺序
patterns : 定义多个模式匹配串
advice : 定义增强
order : 切面在织入时对应的顺序
7.4.5 动态切面
使用DefaultPointcutAdvisor和DynamicMethodMatcherPointcut来完成动态切面
Spring会在创建代理织入切面时,对目标类中的所有方法进行静态切点检查(包括类匹配,方法匹配)
在生成织入切面的代理对象后,第一次调用代理类的每一个方法时都会进行一次静态切点检查。如果本次检查后能排除该方法,则以后对该方法的调用不会再执行静态切点检查。而那些符合的,后续的每次调用,都将执行动态切点检查。
如果没有覆盖getClassFilte()和matches(Method method, Class clazz),则每次调用执行动态检查,影响性能。
在生成织入切面的代理对象后,第一次调用代理类的每一个方法时都会进行一次静态切点检查。如果本次检查后能排除该方法,则以后对该方法的调用不会再执行静态切点检查。而那些符合的,后续的每次调用,都将执行动态切点检查。
如果没有覆盖getClassFilte()和matches(Method method, Class clazz),则每次调用执行动态检查,影响性能。
springDemo
7.4.6 流程切面
使用DefaultPointcutAdvisor和ControlFlowPointcut来完成动态切面
ControlFlowPointCut(Class clazz) : 指定一个类作为流程切点
ControlFlowPointCut(Class clazz, String methodName) : 指定一个类和某一个方法作为流程切点
ControlFlowPointCut(Class clazz, String methodName) : 指定一个类和某一个方法作为流程切点
springDemo
7.4.7 复合切点切面
ComposablePointcut可以将多个切点以并集或交集的方式组合起来
ComposablePointcut本身也是一个切点
ComposablePointcut() : 匹配所有类所有方法的复合切点
ComposablePointcut(ClassFilter classFilter) : 匹配特定类所有方法的复合切点
ComposablePointcut(MethodMatcher methodMatcher) : 匹配所有特定方法的复合切点
ComposablePointcut(ClassFilter classFilter, MethodMatcher methodMathcer) :
匹配特定类特定方法的复合切点
ComposablePointcut本身也是一个切点
ComposablePointcut() : 匹配所有类所有方法的复合切点
ComposablePointcut(ClassFilter classFilter) : 匹配特定类所有方法的复合切点
ComposablePointcut(MethodMatcher methodMatcher) : 匹配所有特定方法的复合切点
ComposablePointcut(ClassFilter classFilter, MethodMatcher methodMathcer) :
匹配特定类特定方法的复合切点
ComposablePointcut提供了3个交集运算的方法:
ComposablePointcut intersection(ClassFilter filter) :
将复合切点和一个ClassFilter对象进行交集运算,得到结果复合切点
ComposablePointcut intersection(MethodMatcher mm) :
将复合切点和一个MethodMatcher对象进行交集运算,得到结果复合切点
ComposablePointcut intersection(Pointcut other) :
将复合切点和一个切点对象进行交集运算,得到一个结果复合切点
ComposablePointcut intersection(ClassFilter filter) :
将复合切点和一个ClassFilter对象进行交集运算,得到结果复合切点
ComposablePointcut intersection(MethodMatcher mm) :
将复合切点和一个MethodMatcher对象进行交集运算,得到结果复合切点
ComposablePointcut intersection(Pointcut other) :
将复合切点和一个切点对象进行交集运算,得到一个结果复合切点
ComposablePointcut提供了两个并集运算方法:
ComposablePointcut union(ClassFilter filter) :
将复合切点和一个ClassFilter对象进行交并集运算,得到一个结果复合切点
ComposablePointcut union(MethodMatcher mm) :
将复合切点和一个MethodMatcher对象进行交并集运算,得到一个结果复合切点
ComposablePointcut union(ClassFilter filter) :
将复合切点和一个ClassFilter对象进行交并集运算,得到一个结果复合切点
ComposablePointcut union(MethodMatcher mm) :
将复合切点和一个MethodMatcher对象进行交并集运算,得到一个结果复合切点
两个切点的交并集运算通过 Pointcuts工具类 :
Pointcut intersection(Pointcut a, Pointcut b) :
对两个切点进行交集运算
Pointcut union(Pointcut a, Pointcut b) :
对两个切点进行并集运算
Pointcut intersection(Pointcut a, Pointcut b) :
对两个切点进行交集运算
Pointcut union(Pointcut a, Pointcut b) :
对两个切点进行并集运算
7.4.8 引介切面
使用DefaultPointcutAdvisor和DynamicMethodMatcherPointcut来完成动态切面
Spring会在创建代理织入切面时,对目标类中的所有方法进行静态切点检查(包括类匹配,方法匹配)
在生成织入切面的代理对象后,第一次调用代理类的每一个方法时都会进行一次静态切点检查。如果本次检查后能排除该方法,则以后对该方法的调用不会再执行静态切点检查。而那些符合的,后续的每次调用,都将执行动态切点检查。
如果没有覆盖getClassFilte()和matches(Method method, Class clazz),则每次调用执行动态检查,影响性能。
在生成织入切面的代理对象后,第一次调用代理类的每一个方法时都会进行一次静态切点检查。如果本次检查后能排除该方法,则以后对该方法的调用不会再执行静态切点检查。而那些符合的,后续的每次调用,都将执行动态切点检查。
如果没有覆盖getClassFilte()和matches(Method method, Class clazz),则每次调用执行动态检查,影响性能。
springDemo
7.5 自动创建代理
8 基于@AspectJ和Schema的AOP
8.3 使用@AspectJ
8.3.3 通过配置使用@AspectJ切面
第一种: 配置切面bean,配置自动代理创建器
<bean class="me.leifgao.PreGreetingAspect">
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator">
<bean class="me.leifgao.PreGreetingAspect">
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator">
第二种: 配置切面bean,配置自动代理创建器
<bean class="me.leifgao.PreGreetingAspect">
<aop:aspectj-autoproxy>
<aop:aspectj-autoproxy>有一个属性proxy-target-class,默认是false,代表使用JDK动态代理,
true,代表使用cglib动态代理。但即使为flase,如果目标类没有申明接口,则自动使用cglib动态代理
<bean class="me.leifgao.PreGreetingAspect">
<aop:aspectj-autoproxy>
<aop:aspectj-autoproxy>有一个属性proxy-target-class,默认是false,代表使用JDK动态代理,
true,代表使用cglib动态代理。但即使为flase,如果目标类没有申明接口,则自动使用cglib动态代理
8.4 @AspectJ语法基础
8.4.1 切点表达式函数
切点表达式由关键字和操作数组成
execution(* greetTo(..)), execution为关键字,“* greetTo(..)”为操作数
execution(* greetTo(..)), execution为关键字,“* greetTo(..)”为操作数
9个@AspectJ切点表达式函数,大致分为4类:
方法切点函数:通过目标类方法的信息定义连接点
方法入参切点函数:通过目标类方法入参定义连接点
目标类切点函数:通过目标类的类型定义连接点
代理类切点函数:通过目标类的代理类定义连接点
方法切点函数:通过目标类方法的信息定义连接点
方法入参切点函数:通过目标类方法入参定义连接点
目标类切点函数:通过目标类的类型定义连接点
代理类切点函数:通过目标类的代理类定义连接点
类别 函数 入参 说明
------------------------------------------------------------------------------------
方法切点函数 execution() 方法名正则串 目标类中所有符合正则串的方法
@annotation() 注解的类名 目标类中所有标注了该注解的方法
方法入参切点函数 args() 类名 目标类方法的入参符合该类型的所有方法
@args() 注解的类名 目标类的方法的入参标注了该注解的所有方法
目标类切点函数 within() 类名正则串 符合类名正则串的所有类的所有方法
target() 类名 目标类匹配类名,则目标类及其子类所有方法
@within() 注解的类名 目标类标注了该注解,则目标类及其子类所有方法
@target() 注解的类名 目标类标注了该注解,则目标类所有方法
代理类切点函数 this() 类名
------------------------------------------------------------------------------------
方法切点函数 execution() 方法名正则串 目标类中所有符合正则串的方法
@annotation() 注解的类名 目标类中所有标注了该注解的方法
方法入参切点函数 args() 类名 目标类方法的入参符合该类型的所有方法
@args() 注解的类名 目标类的方法的入参标注了该注解的所有方法
目标类切点函数 within() 类名正则串 符合类名正则串的所有类的所有方法
target() 类名 目标类匹配类名,则目标类及其子类所有方法
@within() 注解的类名 目标类标注了该注解,则目标类及其子类所有方法
@target() 注解的类名 目标类标注了该注解,则目标类所有方法
代理类切点函数 this() 类名
8.4.2 在表达式函数中使用通配符
* :匹配任意字符,但是只是一个元素
.. : 匹配任意字符,可以匹配多个元素。表示类时,必须和*联合使用,表示入参时,可单独使用
+: 匹配指定类和该类的子类
.. : 匹配任意字符,可以匹配多个元素。表示类时,必须和*联合使用,表示入参时,可单独使用
+: 匹配指定类和该类的子类
@Aspect按支持程度分三类:
支持所有通配符:execution() 和 within()
仅支持"+"通配符: args(), this(), target()
不支持通配符:@args(), @within(), @target(), @annotation()
支持所有通配符:execution() 和 within()
仅支持"+"通配符: args(), this(), target()
不支持通配符:@args(), @within(), @target(), @annotation()
8.4.3 逻辑运算符
&& : 与操作,xml中是 &&
|| : 或操作
!: 非操作
8.4.4 不同的增强类型
@Before : 前置增强
@AfterReturning : 后置增强,pointcut会覆盖 value值
@Around : 环绕增强
@AfterThrowing : 抛出增强,pointcut会覆盖value值
@After : 不关抛出异常还是正常返回,该增强都会执行。
@DeclareParents : 引介增强
8.5 切点函数详解
8.5.1 @annotation()
@annotation()表示标注了某个注解的所有方法
8.5.2 execution()
execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
除了 返回类型模式,方法名模式,参数模式不可省略,其他都可省略
除了 返回类型模式,方法名模式,参数模式不可省略,其他都可省略
1,通过方法签名定义切点
2,通过类定义切点
3,通过类包定义切点
4,通过方法入参定义切点
2,通过类定义切点
3,通过类包定义切点
4,通过方法入参定义切点
8.5.3 args()和@args()
args() 目标类方法入参是指定类(包含子类)时,切点匹配
@args() 目标类方法入参标注了指定的注解时,切点匹配
入参类型点:方法签名中入参类型在继承树中的位置
注解点:标注了注解的类在继承树中的位置
入参类型点 低于 注解点 不能匹配
入参类型点 高于 注解点 注解点所在类及子孙类都匹配
入参类型点:方法签名中入参类型在继承树中的位置
注解点:标注了注解的类在继承树中的位置
入参类型点 低于 注解点 不能匹配
入参类型点 高于 注解点 注解点所在类及子孙类都匹配
8.5.4 within()
within(<类匹配模式>):连接点的最小范围只能是类
不匹配子类??
不匹配子类??
8.5.5 @within()和@target()
@target(M) : 标注了@M的目标类
@within(M) : 标注了@M的目标类及子孙类
@within(M) : 标注了@M的目标类及子孙类
8.5.6 target() 和 this()
target(M):如果目标类按类型匹配M,则目标类所有方法都匹配
包含子孙类
包含子孙类
this(M) :
8.6 @AspectJ进阶
8.6.1 切点复合运算
&& , ||, !
8.6.2 切点命名
匿名切点:直接在增强处定义的切点
@Pointcut("within(xxx)")
private void inPackage(){}
private void inPackage(){}
8.6.3 增强织入顺序
同一个切面类中,按照定义的顺序织入
不同切面中,如果继承了org.springframework.core.Ordered接口,则由接口方法的顺序号决定(小的先织入)
不同切面中,如果没有继承org.springframework.core.Ordered接口,则不确定
8.6.4 访问连接点信息
1,JoinPoint
Object[] getArgs() : 获取连接点方法运行时的入参列表
Signature getSignature(): 获取连接点的方法签名对象
Object getTarget() : 获取连接点所在的目标对象
Object getThis() : 获取代理对象自身
Object[] getArgs() : 获取连接点方法运行时的入参列表
Signature getSignature(): 获取连接点的方法签名对象
Object getTarget() : 获取连接点所在的目标对象
Object getThis() : 获取代理对象自身
1,ProceedingJoinPoint 比 JoinPoint多了两个方法:
Object proceed() throws Throwable : 执行目标对象的连接点处的方法
Object proceed(Object[] args) throws Throwable : 使用新参数执行目标对象的方法
Object proceed() throws Throwable : 执行目标对象的连接点处的方法
Object proceed(Object[] args) throws Throwable : 使用新参数执行目标对象的方法
8.6.5 绑定连接点方法入参
args() 绑定连接点方法的入参
@annotation()绑定连接点方法的注解
@args()绑定连接点方法的入参的注解
@annotation()绑定连接点方法的注解
@args()绑定连接点方法的入参的注解
8.6.6 绑定代理对象
this()或target()函数可绑定被代理对象的实例,也就是目标类
8.6.7 绑定类注解对象
@within()和@target()函数可以将目标类注解对象绑定到增强方法上
8.6.8 绑定返回值
@AfterReturning( returning="retVal")
8.6.9 绑定抛出的异常
@AfterThrowing(throwing = "xxx")
8.7 基于Schema配置切面
8.7.1 一个简单切面的配置
见P301
8.7.2 配置命名切点
<aop:config>中的顺序
<aop:pointcut> , <aop:advisor> , <aop:aspect>
<aop:pointcut> , <aop:advisor> , <aop:aspect>
8.7.3 各种增强类型的配置
后置增强
<aop:after-returning method="xxx" pointcut="xxx" returing="xxx"/>
<aop:after-returning method="xxx" pointcut="xxx" returing="xxx"/>
环绕增强
<aop:around method="xxx" pointcut="xxx"/>
<aop:around method="xxx" pointcut="xxx"/>
抛出异常增强
<aop:after-throwing method="xxx" pointcut="xxx" throwing="xxx"/>
<aop:after-throwing method="xxx" pointcut="xxx" throwing="xxx"/>
Final增强
<aop:after method="xxx" pointcut="xxx"/>
<aop:after method="xxx" pointcut="xxx"/>
引介增强
<aop:declare-parents implement-interface="xxx" default-impl="xxx"
types-matching=""/>
<aop:declare-parents implement-interface="xxx" default-impl="xxx"
types-matching=""/>
8.7.4 绑定连接点信息
后置增强
<aop:after-returning method="xxx" pointcut="xxx" returing="xxx"/>
<aop:after-returning method="xxx" pointcut="xxx" returing="xxx"/>
环绕增强
<aop:around method="xxx" pointcut="xxx"/>
<aop:around method="xxx" pointcut="xxx"/>
抛出异常增强
<aop:after-throwing method="xxx" pointcut="xxx" throwing="xxx"/>
<aop:after-throwing method="xxx" pointcut="xxx" throwing="xxx"/>
Final增强
<aop:after method="xxx" pointcut="xxx"/>
<aop:after method="xxx" pointcut="xxx"/>
引介增强
<aop:declare-parents implement-interface="xxx" default-impl="xxx"
types-matching=""/>
<aop:declare-parents implement-interface="xxx" default-impl="xxx"
types-matching=""/>
8.7.5 Advisor配置
advisor 切点和增强的复合体,包含一个切点,一个增强
8.8 混合切面类型
四种定义切面的方式:
1,基于@AspectJ注解的方式
2,基于<aop:aspect>的方式
3,基于<aop:advisor>的方式
4,基于Advisor类的方式
1,基于@AspectJ注解的方式
2,基于<aop:aspect>的方式
3,基于<aop:advisor>的方式
4,基于Advisor类的方式
11 Spring的事务管理
11.1 数据库事务基础知识
11.1.1何为数据库事务
多条SQL,要么都执行成功,要么执行失败
数据库事务满足四个特性:
1,原子性 :
2,一致性:事务操作后,数据库所处的状态和他的业务规则是一致的
3,隔离性:在并发数据操作时,不同的事务拥有各自的事务空间,互相不影响。隔离级别越高,数据一致性越好,但并发性越弱。
4,持久性:事务提交成功后,事务中的所有数据都必须持久化到数据库中。
1,原子性 :
2,一致性:事务操作后,数据库所处的状态和他的业务规则是一致的
3,隔离性:在并发数据操作时,不同的事务拥有各自的事务空间,互相不影响。隔离级别越高,数据一致性越好,但并发性越弱。
4,持久性:事务提交成功后,事务中的所有数据都必须持久化到数据库中。
11.1.2数据并发问题
1.脏读(dirty read)
A事务读取B事务尚未提交的更改数据。
A事务读取B事务尚未提交的更改数据。
2.不可重复读(unrepeatable read):
A事务读取了B事务已经提交的更改数据
A事务读取了B事务已经提交的更改数据
3.幻想读(phantom read):
A事务读取了B事务新增的数据
A事务读取了B事务新增的数据
4.第一类丢失更新
A事务撤销时,把已经提交的B事务的更新数据覆盖了
A事务撤销时,把已经提交的B事务的更新数据覆盖了
5.第二类丢失更新
A事务提交时,把已经提交的B事务的更新数据覆盖了
A事务提交时,把已经提交的B事务的更新数据覆盖了
11.1.3数据库锁机制
表锁
行锁
行锁
共享锁
独占锁
独占锁
行共享锁:
行独占锁:
表共享锁:
表共享行独占锁定:
表独占锁定:
行独占锁:
表共享锁:
表共享行独占锁定:
表独占锁定:
11.1.4事务隔离级别
11.1.5 JDBC对事务的支持
表锁
行锁
行锁
共享锁
独占锁
独占锁
行共享锁:
行独占锁:
表共享锁:
表共享行独占锁定:
表独占锁定:
行独占锁:
表共享锁:
表共享行独占锁定:
表独占锁定:
11.2 TheradLocal基础知识
11.2.2 ThreadLocal的接口方法
void set(T value):
设置当前线程的线程局部变量的值
设置当前线程的线程局部变量的值
public T get():
返回当前线程所对应的线程局部变量
返回当前线程所对应的线程局部变量
public void remove():
将当前线程局部变量的值删除
将当前线程局部变量的值删除
protected T initialValue():
返回该线程局部变量的初始值
返回该线程局部变量的初始值
11.3 Spring对事务管理的支持
11.3.3 事务同步管理器
Spring的将JDBC的Connection,Hibernate的Session等访问数据库的连接或会话对象统称为资源,这些资源在同一时刻是不能多线程共享的。
11.3.4 事务传播行为
propagation_required : 当前没有事务,则新建一个事务。如果已经存在一个事务,则加入到这个事务中。
propagation_supports : 支持当前事务,如果当前没有事务,则以非事务方式执行。
propagation_mandatory :使用当前事务,如果当前没有事务,则抛出异常
propagation_requires_new :新建事务。如果当前存在事务,则把当前事务挂起
propagation_not_supported :以非事务方式执行操作,如果当前存在事务,则把当前事务挂起
propagation_never :以非事务方式执行。如果当前存在事务,则抛出异常
propagation_nested:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则执行required类似的操作
11.4 编程式的事务管理
TransactionTemplate主要有两个方法:
void setTransactionManager(PlatformTransactionManager transactionManager):
设置事务管理器
Object execute(TransactionCallback action) : 在TransactionCallback回调接口中定义需要以事务方式组织的数据访问逻辑
void setTransactionManager(PlatformTransactionManager transactionManager):
设置事务管理器
Object execute(TransactionCallback action) : 在TransactionCallback回调接口中定义需要以事务方式组织的数据访问逻辑
TransactionCallback只有一个方法
Object doInTransaction(TransactionStatus status)
Object doInTransaction(TransactionStatus status)
11.5 使用XML配置申明式事务
11.5.2 使用原始的TransactionProxyFactoryBean
1.声明式事务配置
声明事务管理器
<bean id = "txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref= "dataSource">
</bean>
需要实施事务增强的目标业务bean
<bean id="xxxTarget"
class="package com.smart.service.xxx"
p:forumDao-ref="xxx"/>
<bean id="bbtForum" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
p:transactionManager-ref="txManager"
p:traget-ref="xxxTraget">
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
声明事务管理器
<bean id = "txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref= "dataSource">
</bean>
需要实施事务增强的目标业务bean
<bean id="xxxTarget"
class="package com.smart.service.xxx"
p:forumDao-ref="xxx"/>
<bean id="bbtForum" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
p:transactionManager-ref="txManager"
p:traget-ref="xxxTraget">
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
2. 异常回滚/提交规则
<prop>内的值应该为:
PROPAGATION, ISOLATION, readOnly, -Exception, +Exception
传播行为 隔离级别(可选) 是否为只读事务(可选) 发生这些异常回滚(可选) 发生这些异常照样提交(可选)
<prop>内的值应该为:
PROPAGATION, ISOLATION, readOnly, -Exception, +Exception
传播行为 隔离级别(可选) 是否为只读事务(可选) 发生这些异常回滚(可选) 发生这些异常照样提交(可选)
11.5.3 基于aop/tx命名空间的配置
1.声明式事务配置
声明事务管理器
<bean id = "txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref= "dataSource">
</bean>
使用切点表达式定义目标bean
<aop : config>
<aop:pointcut id="serviceMethod" expression="execution(xxx)" />
<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice">
</aop : config>
事务增强
<tx : advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="xxx" read-only="false"/>
<tx:method name="add*" rollback-for="Exception"/>
<tx:method name="update*"/>
</tx:attributes>
</tx : advice>
声明事务管理器
<bean id = "txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref= "dataSource">
</bean>
使用切点表达式定义目标bean
<aop : config>
<aop:pointcut id="serviceMethod" expression="execution(xxx)" />
<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice">
</aop : config>
事务增强
<tx : advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="xxx" read-only="false"/>
<tx:method name="add*" rollback-for="Exception"/>
<tx:method name="update*"/>
</tx:attributes>
</tx : advice>
11.6 使用注解配置声明式事务
11.6.1 使用@Transactional注解
对标注了@Transactional注解的Bean进行加工处理,以织入事务管理切面
<tx:annotation-driven transaction-manager="txManager"/>
<tx:annotation-driven>还有另外两个属性
proxy-target-class : 如果为true,则CGLib来创建子类
order : 如果需要织入其他切面,则可以控制顺序
<tx:annotation-driven transaction-manager="txManager"/>
<tx:annotation-driven>还有另外两个属性
proxy-target-class : 如果为true,则CGLib来创建子类
order : 如果需要织入其他切面,则可以控制顺序
@Transactional属性
propagation:事务传播行为
isolation:事务隔离级别
readOnly:事务读写性
timeout:超时时间
rollbackFor:一组异常,遇到时进行回滚,类型为Class<? extends Throwable>[]
rollbackForClassName:一组异常,遇到时回滚,类型为String[]
noRollbackFor:一组异常,允到时不回滚
noRollbackForClassName:一组异常,允到时不回滚
propagation:事务传播行为
isolation:事务隔离级别
readOnly:事务读写性
timeout:超时时间
rollbackFor:一组异常,遇到时进行回滚,类型为Class<? extends Throwable>[]
rollbackForClassName:一组异常,遇到时回滚,类型为String[]
noRollbackFor:一组异常,允到时不回滚
noRollbackForClassName:一组异常,允到时不回滚
Spring建议在具体业务类上使用@Transactional注解,而不是在接口上
类级注解,适用于类中所有public的方法
方法级注解会覆盖类注解
方法级注解会覆盖类注解
12 Spring的事务管理难点剖析
12.4 多线程的疑惑
12.4.1 Spring通过单实例化Bean简化多线程问题
一个类能以单实例的方式运行的前提是“无状态”的,即不能拥有状态化的成员变量
spring通过ThreadLocal将有状态的变量(如Connection等)本地线程化。
12.4.2 启动独立线程调用事务方法
在相同线程中进行相互嵌套调用的事务方法工作在相同的事务中。
如果相互嵌套调用的方法工作在不同的线程中,则不同线程下的事务方法工作在不同的独立的事务中
如果相互嵌套调用的方法工作在不同的线程中,则不同线程下的事务方法工作在不同的独立的事务中
12.6 特殊方法不可Spring AOP事务
12.6.1 哪些方法不能实施SpringAOP事务
基于接口动态代理的AOP事务增强来说
只能是public 或 public final修饰符的方法。
只能是public 或 public final修饰符的方法。
基于CGlib字节码动态代理
使用 final、static、private修饰符的方法不能被子类覆盖,无法实施SpringAop事务增强
使用 final、static、private修饰符的方法不能被子类覆盖,无法实施SpringAop事务增强
12.7 数据连接泄露
12.7.1 底层连接资源的访问问题
Spring DAO的模板(JdbcTemplate、HibernateTemplate等),一定不会存在数据连接泄露问题
获取Spring管理的数据连接,有以下两种方法:
1,使用数据资源获取工具类
2,对数据源进行代理
1,使用数据资源获取工具类
2,对数据源进行代理
12.7.2 Spring JDBC数据连接泄露
jdbcTemplate.getDataSource().getConnection() 这种直接获取的数据连接,如果最终没有释放,会造成数据库连接泄露
12.7.3 事务环境下通过DataSourceUtils获取数据连接
DataSourceUtils类
static Connection doGetConnection(DataSource dataSource) : 首先从事务中获取连接,失败后再从数据源获取连接
static Connnection getConnection(DataSource dataSource):和上面一样
static void doReleaseConnection(Connection con, DataSource dataSource): 释放连接,放回到连接池中
static void releaseConnection(Connection con, DataSource dataSource):和上面一样
static Connection doGetConnection(DataSource dataSource) : 首先从事务中获取连接,失败后再从数据源获取连接
static Connnection getConnection(DataSource dataSource):和上面一样
static void doReleaseConnection(Connection con, DataSource dataSource): 释放连接,放回到连接池中
static void releaseConnection(Connection con, DataSource dataSource):和上面一样
通过DataSourceUtils类获得的连接,不会存在泄露的情况(前提,在事务中获取)
12.7.4 无事务环境下通过DataSourceUtils获取数据连接
在非事务环境下,通过DataSourceUtils类获得的连接,也有可能会存在泄露的情况
需要显示调用 DataSourceUtils.releaseConnection()方法释放获取的连接。
12.7.5 JdbcTemplate如何方式数据泄露
在执行后,会调用DataSourceUtils#releaseConnection()方法释放连接
12.7.6 使用TransactionAwareDataSourceProxy
通过TransactionAwareDataSourceProxy代理的bean去获取数据库连接,和DataSourceUtils.getConnection()方法获取连接效果一样的。
13 使用Spring JDBC访问数据库
13.1 使用Spring JDBC
13.1.2 在DAO中使用JdbcTemplate
JdbcTemplate的属性:
queryTimeout : 设置JdbcTemplate所创建的Statement查询数据时的最大超时时间
fetchSize : 设置底层的ResultSet每次从数据库返回的行数。
maxRows : 设置底层的ResultSet从数据库返回的最大行数
ignoreWarnings : 是否忽略SQL的警告信息
queryTimeout : 设置JdbcTemplate所创建的Statement查询数据时的最大超时时间
fetchSize : 设置底层的ResultSet每次从数据库返回的行数。
maxRows : 设置底层的ResultSet从数据库返回的最大行数
ignoreWarnings : 是否忽略SQL的警告信息
13.2 基本的数据操作
13.2.1 更改数据
update(String sql, Object[] args)
13.2.2 返回数据库的表自增主键值
int executeUpdate(String sql, int autoGeneratedKeys)
PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
autoGeneratedKeys 设置为
Statement.RETURN_GENERATED_KEYS : 绑定数据库产生的主键值
Statement.NO_GENERATED_KEYS时,不绑定主键
Statement.RETURN_GENERATED_KEYS : 绑定数据库产生的主键值
Statement.NO_GENERATED_KEYS时,不绑定主键
13.2.3 批量更改数据
public int[] batchUpdate(String[] sql) : 多条sql语句组成一个数组,该方法批量方式执行SQL语句
int[] batchUpdate(String sql, BatchPreparedStatementSetter pss) : 使用该方法对于同一结构的带参数SQL语句多次进行数据更新操做
14 整合其他ORM框架
14.1 Spring整合ORM技术
1.方便基础设施的搭建
1.方便基础设施的搭建
2.异常封装
3.统一的事务管理
4.允许混合使用多个ORM框架
14.3 在Spring中使用MyBatis
14.3.1 配置SqlMapClient
每个MyBatis的应用都是以一个SqlSessionFactory对象的实例为核心。
提供可控制MyBatis框架运行行为的属性信息
<settings>
<setting name="lazyLoadingEnabled" value="false">
</settings>
定义全限定类名的别名,在映射文件中可以通过别名代替具体的类名
<typeAliases>
<typeAlias alias="Forum" type="org.xxx.xxx.Forum">
<typeAlias alias="Topic" type="org.xxx.xxx.Topic">
</typeAliases>
将MyBatis的所有映射文件组装起来
<mappers>
<mapper resource="org/xxx/xxx/Forum.xml">
<mapper resource="org/xxx/xxx/Topic.xml">
</mappers>
<settings>
<setting name="lazyLoadingEnabled" value="false">
</settings>
定义全限定类名的别名,在映射文件中可以通过别名代替具体的类名
<typeAliases>
<typeAlias alias="Forum" type="org.xxx.xxx.Forum">
<typeAlias alias="Topic" type="org.xxx.xxx.Topic">
</typeAliases>
将MyBatis的所有映射文件组装起来
<mappers>
<mapper resource="org/xxx/xxx/Forum.xml">
<mapper resource="org/xxx/xxx/Topic.xml">
</mappers>
resultType指定返回值
parameterType指定入参类型 : 在sql中通过#{xxx}绑定parameterType参数,支持级联属性,如#{topic.forumId}
parameterType指定入参类型 : 在sql中通过#{xxx}绑定parameterType参数,支持级联属性,如#{topic.forumId}
14.3.2 在Spring中配置MyBatis
bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p : dataSource-ref="xxx"
p : configLocation="classpath : myBatisConfig.xml"
p : mapperLocations="classpath : xxx/xxx/xx/*.xml"/>
p : dataSource-ref="xxx"
p : configLocation="classpath : myBatisConfig.xml"
p : mapperLocations="classpath : xxx/xxx/xx/*.xml"/>
14.3.3 编写MyBatis的DAO
<bean class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory"/>
</bean>
<constructor-arg ref="sqlSessionFactory"/>
</bean>
List<?> selectList(String statement, Object parameter) :
statemet:xml映射文件的空间命名和id
parameter:传递的参数
int insert(String statement, Object parameter) :
调用映射项,返回插入的记录数
int update(String statement, Object parameter):
调用update映射项,返回更改的记录数
statemet:xml映射文件的空间命名和id
parameter:传递的参数
int insert(String statement, Object parameter) :
调用映射项,返回插入的记录数
int update(String statement, Object parameter):
调用update映射项,返回更改的记录数
定义一个接口,与xml文件匹配
sessionTemplate.getMapper(xxxDao.class) : 将返回xxxDao接口的实例方法
sessionTemplate.getMapper(xxxDao.class) : 将返回xxxDao接口的实例方法
MapperScannerConfigurer 将映射接口转换为Spring容器中的Bean。
14.4 DAO层设计
14.4.1 DAO基类设计
每个MyBatis的应用都是以一个SqlSessionFactory对象的实例为核心。
resultType指定返回值
parameterType指定入参类型 : 在sql中通过#{xxx}绑定parameterType参数,支持级联属性,如#{topic.forumId}
parameterType指定入参类型 : 在sql中通过#{xxx}绑定parameterType参数,支持级联属性,如#{topic.forumId}
14.3.2 在Spring中配置MyBatis
bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p : dataSource-ref="xxx"
p : configLocation="classpath : myBatisConfig.xml"
p : mapperLocations="classpath : xxx/xxx/xx/*.xml"/>
p : dataSource-ref="xxx"
p : configLocation="classpath : myBatisConfig.xml"
p : mapperLocations="classpath : xxx/xxx/xx/*.xml"/>
14.3.3 编写MyBatis的DAO
<bean class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory"/>
</bean>
<constructor-arg ref="sqlSessionFactory"/>
</bean>
List<?> selectList(String statement, Object parameter) :
statemet:xml映射文件的空间命名和id
parameter:传递的参数
int insert(String statement, Object parameter) :
调用映射项,返回插入的记录数
int update(String statement, Object parameter):
调用update映射项,返回更改的记录数
statemet:xml映射文件的空间命名和id
parameter:传递的参数
int insert(String statement, Object parameter) :
调用映射项,返回插入的记录数
int update(String statement, Object parameter):
调用update映射项,返回更改的记录数
定义一个接口,与xml文件匹配
sessionTemplate.getMapper(xxxDao.class) : 将返回xxxDao接口的实例方法
sessionTemplate.getMapper(xxxDao.class) : 将返回xxxDao接口的实例方法
MapperScannerConfigurer 将映射接口转换为Spring容器中的Bean。
15 Spring Cache
15.1 缓存概述
15.2 掌握Spring Cache抽象
15.2.1 缓存注解
只有public方法的结果可以缓存,其他的不行
@Cacheable:
加上了该注解的方法将缓存结结果
缓存key的生成规则:
1,没有入参,则使用SimpleKey.EMPTY作为key
2,只有一个入参,则使用该入参作为key
3,多个入参,返回包含所有入参的SimpleKey
带条件的缓存
Cacheable(condition="xxx")
加上了该注解的方法将缓存结结果
缓存key的生成规则:
1,没有入参,则使用SimpleKey.EMPTY作为key
2,只有一个入参,则使用该入参作为key
3,多个入参,返回包含所有入参的SimpleKey
带条件的缓存
Cacheable(condition="xxx")
@CachePut :首先执行方法,然后将返回值放入缓存
@CacheEvict :删除缓存中的值
allEntries :删除所有缓存
beforeInvocation :在调用方法前,清除缓存
allEntries :删除所有缓存
beforeInvocation :在调用方法前,清除缓存
@Caching :是一个组注解,包含@Cacheable、@CacheEvict、@CachePut注解的数组
@CacheConfig :类注解,提供该类中所有缓存方法的配置信息
15.2.2 缓存管理器
SimpleCacheManager :
通过SimpleCacheManager配置多个缓存列表。
通过SimpleCacheManager配置多个缓存列表。
NoOpCacheManager :
测试,不缓存任何数据。
测试,不缓存任何数据。
ConcurrentmapCacheManager :
不需要定义缓存列表,默认使用JDK的ConcurrentMap。
不需要定义缓存列表,默认使用JDK的ConcurrentMap。
CompositeCacheManager :
可以组合配置多个上面的Manager
可以组合配置多个上面的Manager
15.2.4 基于XML的Cache声明
<bean id="userService" class="xxx.xxx.xxx"/>
缓存定义
<cache:advice id="cacheAdvice" cache-manager="cacheManager"/>
<cache : caching cache="users">
<cache : cacheable method="findUser" key="#userId">
<cache : cache-evict method="loadUsers" all-entries="true"/>
</cache : caching>
</cache:advice>
<aop:config>
<aop:advisor advice-ref="cacheAdvice"
pointcut="xxxx"/>
</aop:config>
缓存定义
<cache:advice id="cacheAdvice" cache-manager="cacheManager"/>
<cache : caching cache="users">
<cache : cacheable method="findUser" key="#userId">
<cache : cache-evict method="loadUsers" all-entries="true"/>
</cache : caching>
</cache:advice>
<aop:config>
<aop:advisor advice-ref="cacheAdvice"
pointcut="xxxx"/>
</aop:config>
15.2.5 以编程的方式初始化缓存
15.2.6 自定义缓存注解
15.3 配置Cache存储
15.3.1 缓存注解
只有public方法的结果可以缓存,其他的不行
@Cacheable:
加上了该注解的方法将缓存结结果
缓存key的生成规则:
1,没有入参,则使用SimpleKey.EMPTY作为key
2,只有一个入参,则使用该入参作为key
3,多个入参,返回包含所有入参的SimpleKey
带条件的缓存
Cacheable(condition="xxx")
加上了该注解的方法将缓存结结果
缓存key的生成规则:
1,没有入参,则使用SimpleKey.EMPTY作为key
2,只有一个入参,则使用该入参作为key
3,多个入参,返回包含所有入参的SimpleKey
带条件的缓存
Cacheable(condition="xxx")
@CachePut :首先执行方法,然后将返回值放入缓存
@CacheEvict :删除缓存中的值
allEntries :删除所有缓存
beforeInvocation :在调用方法前,清除缓存
allEntries :删除所有缓存
beforeInvocation :在调用方法前,清除缓存
@Caching :是一个组注解,包含@Cacheable、@CacheEvict、@CachePut注解的数组
@CacheConfig :类注解,提供该类中所有缓存方法的配置信息
15.2.2 缓存管理器
SimpleCacheManager :
通过SimpleCacheManager配置多个缓存列表。
通过SimpleCacheManager配置多个缓存列表。
NoOpCacheManager :
测试,不缓存任何数据。
测试,不缓存任何数据。
ConcurrentmapCacheManager :
不需要定义缓存列表,默认使用JDK的ConcurrentMap。
不需要定义缓存列表,默认使用JDK的ConcurrentMap。
CompositeCacheManager :
可以组合配置多个上面的Manager
可以组合配置多个上面的Manager
15.2.4 基于XML的Cache声明
<bean id="userService" class="xxx.xxx.xxx"/>
缓存定义
<cache:advice id="cacheAdvice" cache-manager="cacheManager"/>
<cache : caching cache="users">
<cache : cacheable method="findUser" key="#userId">
<cache : cache-evict method="loadUsers" all-entries="true"/>
</cache : caching>
</cache:advice>
<aop:config>
<aop:advisor advice-ref="cacheAdvice"
pointcut="xxxx"/>
</aop:config>
缓存定义
<cache:advice id="cacheAdvice" cache-manager="cacheManager"/>
<cache : caching cache="users">
<cache : cacheable method="findUser" key="#userId">
<cache : cache-evict method="loadUsers" all-entries="true"/>
</cache : caching>
</cache:advice>
<aop:config>
<aop:advisor advice-ref="cacheAdvice"
pointcut="xxxx"/>
</aop:config>
15.2.5 以编程的方式初始化缓存
15.2.6 自定义缓存注解
16 任务调度和异步执行器
16.2 Quartz快速进阶
16.2.1 Quartz基础结构
Job :
execute(JobExecutionContext context):通过实现该接口执行任务
execute(JobExecutionContext context):通过实现该接口执行任务
JobDetail :
Quartz在每次执行Job时,都重新创建一个Job实例,JobDetail接受一个Job的实现类,而不是实例。
Quartz在每次执行Job时,都重新创建一个Job实例,JobDetail接受一个Job的实现类,而不是实例。
Trigger :
触发器,时间规则
触发器,时间规则
Scheduler :
代表一个Quartz独立运行容器,Trigger和JobDetail可以注册到Scheduler中
代表一个Quartz独立运行容器,Trigger和JobDetail可以注册到Scheduler中
Job有一个StatefulJob子接口,代表有状态任务。
无状态任务在执行时拥有自己的JobDataMap复制,对JobDataMap的更改不影响下次执行。
有状态任务共享同一个JobDataMap实例,每次执行对JobDataMap的更改会影响下次执行。
无状态任务在执行时拥有自己的JobDataMap复制,对JobDataMap的更改不影响下次执行。
有状态任务共享同一个JobDataMap实例,每次执行对JobDataMap的更改会影响下次执行。
一个Scheduler可以拥有多个 Trigger和多个JobDetail,可以分到不同的组中。组名和名称组成了对象的全名。同一个对象的全名不能相同。
16.2.2 使用SimpleTrigger
SimpleTrigger(String name, String group): 指定Trigger所属组合名称
SimpleTrigger(String name, String group, Date startTime):
指定触发时间
SimpleTrigger(String name, Strign group, Date startTime, Date endTime, int repeatCount, long repeatInterval):
指定结束时间,重复执行次数,时间间隔
SimpleTrigger(String name, String group, Date startTime):
指定触发时间
SimpleTrigger(String name, Strign group, Date startTime, Date endTime, int repeatCount, long repeatInterval):
指定结束时间,重复执行次数,时间间隔
16.2.3 使用CronTrigger
1. Cron表达式
16.2.4 使用Calendar
16.2.5 任务调度信息存储
1. 通过配置文件调整任务调度信息的保存策略
12.查询数据库中的信息
16.3 在Spring中使用Quartz
16.3.1 创建JobDetail JobDetailFactoryBean配置:
<bean id="jobDetail_1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"
p:jobClass="com.smart.quartz.MyJob"
p:applicationContextJobDataKey="applicationContext">
<property name="jobDataAsMap">
<map>
<entry key="size" value="10"/>
</map>
</property>
</bean>
MethodInvokingJobDetailFactoryBean配置
<bean id="jobDetail_1" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"
p:targetObject="myService"
p:targetMethod="doJob"
p:concurrent="false"/>
1. JobDetailFactoryBean
jobDetailFactoryBean扩展与Quartz的JobDetail
具有以下属性:
jobClass : 实现Job接口的任务类
beanName : 默认为bean的id名,对应任务的名称
jobDataAsMap : 任务所对应的JobDataMap提供值
applicationContextJobDataKey : 用户可以将 Spring ApplicationContext的引用保存在JobDataMap中
jobListenerNames : 类型为String[], 注册在Scheduler中的JobListeners名称
jobDetailFactoryBean扩展与Quartz的JobDetail
具有以下属性:
jobClass : 实现Job接口的任务类
beanName : 默认为bean的id名,对应任务的名称
jobDataAsMap : 任务所对应的JobDataMap提供值
applicationContextJobDataKey : 用户可以将 Spring ApplicationContext的引用保存在JobDataMap中
jobListenerNames : 类型为String[], 注册在Scheduler中的JobListeners名称
<bean id="jobDetail_1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"
p:jobClass="com.smart.quartz.MyJob"
p:applicationContextJobDataKey="applicationContext">
<property name="jobDataAsMap">
<map>
<entry key="size" value="10"/>
</map>
</property>
</bean>
<bean id="jobDetail_1" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"
p:targetObject="myService"
p:targetMethod="doJob"
p:concurrent="false"/>
16.3.2 创建Trigger
SimpleTriggerFactoryBean配置
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"
p:jobDetail-ref="jobDetail_1"
p:startDelay="1000"
p:repeatInterval="2000"
p:repeatCount="100">
<property name="jobDataAsMap">
<map>
<entry key="count" value="10"/>
</map>
</property>
</bean>
p:jobDetail-ref="jobDetail_1"
p:startDelay="1000"
p:repeatInterval="2000"
p:repeatCount="100">
<property name="jobDataAsMap">
<map>
<entry key="count" value="10"/>
</map>
</property>
</bean>
CronTriggerFactoryBean配置
<bean id="checkImagesTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"
p:jobDetail-ref="jobDetail_1"
p:cronExpression="0/5 * * * * ?"/>
<bean id="checkImagesTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"
p:jobDetail-ref="jobDetail_1"
p:cronExpression="0/5 * * * * ?"/>
16.3.3 创建Scheduler
0 条评论
下一页