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