Day01:
1:Spring(Rode Johoson)是什么:开源的,用来简化企业级开发的,分层的,轻量级的框架;(sourceforge.net|open-open.com开源网站);
轻量级是相对于传统的(比如Jboss,weblogic),它占用的资源少,是一种非侵入式框架;
框架:一个软件的半成品;
2:为什么 要使用spring:a:对大量的企业级服务作了再次的封装(事务,安全,日志,消息,任务管理,邮件,通讯,数据访问)。
a1:简化了API(提供了更方便的接口来使用企业级服务); a2:处理很多细节问题(异常处理,资源的获取与释放);
b:提供了一个轻量级的容器,支持IOC(控制反转|DI:依赖注入)和AOP(面向切面编程),通过IOC可以使得应用程序中的各个模块松散耦合在一起,
方便维护与测试;通过AOP,可以为模块提供声明式的基础服务(事务,安全);
c:spring是一个框架,支持企业级开发的各个方面:即可以使用spring全部功能,也可以只使用其部分功能;
c1:对表示层:支持struts,jsf... 自身实现spring mvc;
c2:对业务层:支持事务,安全|支持IOC,AOP|支持任务管理,消息服务,远程调用...支持实例池...
c3:对持久层:支持hibernate/ibatis,支持JDBC
c4:对动态语言:工作流等等第三方产品提供了集成
d:是一个非侵入式的解决方案
3:spring的组成:
Spring IoC内容:一:概念,分类
1:什么是IOC:Inversion of Control控制反转又称依赖注入
a:对象之间的依赖关系交给程序的外部(容器框架)
b:容器在运行时,依据配置,动态地建立对象之间的依赖关系;
IOC优点:a:模块之间的关系松散耦合;b:易测试
2:分类(IOC的实现):a:基于set方法 b:基于构造器
二:IOC的基本使用(基本装配)
a:容器:分类:BeanFactory|ApplicationContext|Web 获得:配置文件(xml) ,实例化ClassPathXmlApplicationContext.getBean()获得一个对象
装配方式:
1:基于set方法:
A:对于基本类型(8种+String)
<property name="属性名">
<value>值</value>
</property> (自动做类型转换)
<!-- id唯一 | 不允许出现“/”等特殊字符,可以使用以name来命名 |bean name="s1,s2,s3" -->
<bean id="someBean" class="ioc1.SomeBean" init-method="init" destroy-method="cleanup">
// Bean类要求提供一个缺省构造器init()做一些初始化操作:获得资源|cleanup()在Bean被销毁之前,被调用,用业释放资源
<property name="str1">
<value>string1</value>
</property>
<property name="val1">
<value>100</value>
</property>
</bean>
///
<property name="str1" value="string1"/>
ac.registerShutdownHook();后调用destroy-method方法
B:对象类型
<property name="属性名">
a:<ref local="id(被注入的Bean的名称)"/>|只会在当前的配置文件中查找id
b:<ref bean="id"/>|搜索所有已加载的配置文件<property name="ob" ref="otherBean"/><!-- ref bean -->
c:嵌套被注入Bean的定义|被嵌套的Bean只能被所在的Bean使用
</property> (自动做类型转换)
c:集合类型
List(a:可以注入基本类型的包装类,对象,集合类型|b:如果使用泛型只能注入对应类型|c:有序,允许重复元素),
<property name="listProperty">
<list>
<value>string1</value>
<value>string1</value>
<value>string3</value>
</list>
</property>
Set(a:可以注入基本类型的包装类,对象,集合类型|b:如果使用泛型只能注入对应类型|c:无序,不允许重复元素),
<property name="setProperty">
<set>
<value>string1</value>
<value>string1</value>
<value>string3</value>
</set>
</property>
Map,
<property name="mapProperty">
<map>
<entry key="key1">
<value>value1</value>
</entry>
<!-- key是对象
<entry>
<key><ref bean=""/></key>
<value>value2</value>
</entry>
-->
</map>
</property>
key:字符串,用key属性指定;key是对象,用key元素指定
Properties:
<property name="props">
<props>
<prop key="key2">value2</prop>
</props>
</property>
2:基于构造器方式
<Constructor-arg>
<value>,<ref>,<list>
这两种方法比较:Constructor|属性比较多,可能会有过多的构造器|可能会产生循环依赖
示例spring_ioc:ioc2包下:分散配置文件的方式
三:IOC的高级使用(复杂装配)
1:自动装配>提示:byName按属性,byType按属性类型,constructor按构造器中参数类型,autodetect([di'tekt]'发现,发觉)检查Beane有无缺省构造器,有byType,无Constructor
缺点:易出错,配置文件不够清晰;
使用场合:构建系统原型
<bean id="otherBean" class="ioc5.OtherBean">
<property name="val1" value="string1"></property>
</bean>
<bean id="someBean" class="ioc5.SomeBean" />
2:工厂方式的装配:
A:简单工厂step1:产品的创建过程封装 step2:使用spring,配置---》ioc6
<bean id="car" class="ioc6.CarFactory" factory-method="getCar"/><!-- 这个方法必须是一个静态方法 -->
B:实例工厂---》ioc7
3:Bean定义的继承《配置信息》
A:有直接继承关系的
<!-- abstract这个属性在客户端不能实例化了 -->
<bean id="abstractStudent" class="ioc8.Student" abstract="true">
<property name="classes" value="sd1009"/>
</bean>
<bean id="student1" parent="abstractStudent">
<property name="name" value="LWSX"/>
<property name="age" value="23"/>
</bean>
B:没有直接继承关系的---》ioc8
<bean id="abstractBean" abstract="true">
<property name="str1" value="string1"/>
</bean>
<bean id="someBean" class="ioc8.SomeBean" parent="abstractBean">
<property name="val1" value="100"/>
</bean>
Bean的范围
scope=singleton默认《一样的对象》
prototype原型
reguest:当Http请求到达,创建这个Bean,当请求结束 ,销毁
session
global-session(portlet)
四:组件的生命周期
Bean的生命周期:
1:容器先读取配置文件
2:调用BeanFactoryPostProcessor(Bean工厂的后处理Bean)对配置文件进行修正(可选)
3:实例化
4:装配
5:回调方法:
回调接口)
5.1:ApplicationContextAware获得容器的引用
@Override
public void setApplicationContext(ApplicationContext arg0)
throws BeansException {
// 容器调用这个方法
ac=arg0;
}
5.2:BeanPostProcessor(后处理Bean)经常用来扩展容器的功能:在对象初始化之前之后调用
<!-- 注册后处理Bean:让容器知道其存在 -->
<bean class="ioc10.EncryptBean"/>
---------------------------------------------------------------------------------
@Override//Object:被处理的Bean
public Object postProcessAfterInitialization(Object arg0, String arg1)
throws BeansException {
Field[] fields = arg0.getClass().getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
try{
for(int i=0;i<fields.length;i++){
if(fields[i].getType().equals(java.lang.String.class)){
String origVal=(String) fields[i].get(arg0);
String encryptVal=origVal+" encrypted";
fields[i].set(arg0, encryptVal);
}
}
}catch(Exception e){
e.printStackTrace();
}
return arg0;
}
@Override
public Object postProcessBeforeInitialization(Object arg0, String arg1)
throws BeansException {
//什么也不做,不能返回空
return arg0;
}
5.3:BeanFactoryPostProcessor(Bean工厂的后处理):在Bean实例化之前可以去修改Bean的配置
Spring对其实现:
a:分散配置文件:PropertyPlaceholderConfigure
<!-- 读取资源文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="ioc10\\info.properties"/>
</bean>
b:设置属性编辑器:CustomEditorConfigurer
属性编辑器的编程:
A:写一个类,继承java.beans.PropertyEditorSupport(属性编辑器类)覆盖相应方法setAsText--setValue(addr);//设置回去
<bean id="person" class="ioc11.Person">
<property name="addr" value="beijing-dzslwsx"/>---->这里的地址不要用ref了用value
<property name="birthday" value="1989-06-26"></property>
</bean>
B:设置属性编辑器
——————————————————————————————————————————
<!-- 设置属性编辑器类 -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="ioc11.Address" value="ioc11.AddressEditor"/>
<entry key="java.util.Date" value="ioc11.DateEditor"/>
</map>
</property>
</bean>
——————————————————————————————————————————
<!-- 设置属性编辑器类 -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="ioc11.Address">
<bean class="ioc11.AddressEditor"/>
</entry>
<entry key="java.util.Date">
<bean class="ioc11.DateEditor"/>
</entry>
</map>
</property>
</bean>
数组默认已经存在了
6:初始化:init-method="初始化的方法名"
7:就绪
8:销毁:destroy-method="方法名"
五:事件处理机制
优点:最低的耦合
ApplicationListener接口
step1:自定义事件类 继承抽象类ApplicationEvent
step2:写一个监听器类 实现ApplicationListener
step3:Bean调用ApplicationContext来发布事件
示例:spring_ioc:ioc12包
不满足条件发布这个事件ac.publishEvent(new RegisterEvent(this));
--------------------
自定义事件类
public class RegisterEvent extends ApplicationEvent{
public RegisterEvent(Object arg0) {
super(arg0);
// TODO Auto-generated constructor stub
}
}
--------------------
使用监听器处理事件
public class RegisterListener implements ApplicationListener{
public void onApplicationEvent(ApplicationEvent arg0) {
// TODO Auto-generated method stub
if(arg0 instanceof RegisterEvent){
System.out.println("illegale age!");
}
}
}
--------------------
配置文件
<bean id="customerService" class="ioc12.CustomerService"/>
<!-- 注册监听器 -->
<bean class="ioc12.RegisterListener"/>
======================================================================================================================================================================
======================================================================================================================================================================
Spring AOP:
一:AOP思想,相关的概念,优点;
1:什么是AOP?
面向切面编程
★面向切面编程思想:将具体业务逻辑中的交叉业务逻辑(可以被共享,与具体业务无关)抽取出来,封装成切面(包含了交叉业务逻辑+位置),
然后使用AOP容器将切面织入到目标对象(只封装具体业务逻辑);
2:AOP相关概念:8
α:切面┈┈泛指交叉业务逻辑;(Aspect)
β:通知┈┈具体的交叉业务逻辑;(Advice)比如:事务处理通知(TransationAdvice)
γ:连接点┈┈切面可以织入的位置;(方法,属性)(JoinPoint)
δ:切入点┈┈通知可能织入到哪些目标对象哪些方法;(PointCut)
ε:引入┈┈是一种特殊的通知,可以动态地为目标对象来添加新的属性和方法;(Introduction)
ζ:目标对象┈┈(Target)|织入┈┈(weaving)|代理对象┈┈(proxy)
3:AOP如何实现:
①静态织入:特殊的编译器,在编译阶段,将切面代码插入到目标对象的字形码当中。(性能好)代表:"AspectJ";
②动态织入:在运行阶段,通过动态代理机制,将切面代码插入到目标对象,生成一个代理对象;
委托:可以为被委托类(目标类)提供“增值”服务!
代理:特殊的委托,委托类与目标类实现相同的接口!
静态代理|代理类与目标类一一对应
动态代理|由系统依据目标对象以及需要提供的“增值”服务(InvocationHandler接口:制订“增值”如何织入到目标对象的规则);
在运行时来自动生成一个代理对象;(Proxy:具体生成代理对象);
public class LogInvocationHandler implements InvocationHandler{
private Object target;
public LogInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object arg0, Method arg1, Object[] arg2)
throws Throwable {
//织入日志服务
System.out.println(arg1.getName()+"execute at:"+new Date());
Object rsObj=arg1.invoke(target, arg2);
return rsObj;
}
}
------------------------------------------------------------------------
ISomeService target = new SomeServiceImpl();
//arg0:目标对象的ClassLoader|arg1:目标类所实现的接口|arg2:InvocationHander
ISomeService proxy =(ISomeService)
Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new LogInvocationHandler(target));
System.out.println("proxy:"+proxy.getClass().getName());
proxy.doSome();
二:AOP的编程;
1:spring AOP的基本原理(实现机制):
采用动态代理来实现“织入”;
①:默认,采用JDK的Proxy来生成代理对象
②:如果目标类没有实现接口,采用cglib来生成代理对象(有限制:代理对象是目标类的子类,所以目标类不能是final类);
cglib生成的代理对象性能较好|Proxy生成代理对象性能销差
cglib生成代理类时间较长|Proxy生成代理类时间较短
2:通知的使用(只给了交叉业务逻辑)
①:Before:前置通知,在目标方法执行之前执行;
特点:a:不改变目标方法执行的结果|b:不能够阻止目标方法被执行|c:目标方法执行之前执行
MethodBeforeAdvice接口
before(Method method,
Object[] args,
Object target)
throws Throwable
这个接口为我们提供了获得目标方法,参数以及目标对象的机会,由于已经得到了方法参数,所以有机会使用运行时
参数实现通知,然而,你不能改变这些值,也就是你不能替换参数对象,你无法改变这些对象,实现的时候要注意!
MethodBeforeAdvice惟一能阻止目标方法被调用 的途径是抛出异常(或调用System.exit()),但是不希望这样做,
抛出异常的结果依赖抛出的异常的类型,如果异常是RuntimeException或者如果异常是目标方法声明抛出的异常的话,
异常将传播到调用方法。否则,Spring框架将捕获这个异常,并且重新包装在RuntimeException中再次抛出去。
step1:实现接口(before方法)
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
step2:使用ProxyFactoryBean(类似于JDK中的Proxy,可以用配置文件来配置)来织入通知
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
<!-- 置入的过程
step1:配置目标对象-->
<bean id="someServiceTarget" class="aop3.SomeServiceImpl"/>
<!-- step2:配置切面-->
<bean id="logAdvice" class="aop3.LogAdvice"/>
<!-- step3:配置代理-->
<bean id="someService" class="org.springframework.aop.framework.ProxyFactoryBean">
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
<!-- 代理类实现的接口,如果没有实现接口,则不用配置 -->
<property name="proxyInterfaces" value="aop3.ISomeService"/>
<!-- 目标对象 -->
<property name="target" ref="someServiceTarget"/>
<!-- 切面-->
<property name="interceptorNames">
<list>
<value>logAdvice</value>
</list>
</property>
<!-- 改变默认生成代理的机制,强制使用cglib生成代理对象 -->
<property name="proxyTargetClass" value="true"/>
</bean>
②:After-returning:后置通知,在目标方法执行之后执行;
特点:a:不改变目标方法执行的结果|b:不改变目标方法执行的流程|c:目标方法执行之后执行
AfterReturningAdvice接口
afterReturning(Object returnValue,
Method method,
Object[] args,
Object target)
throws Throwable
这个通知给你机会得到调用的方法,传入的参数以及目标对象。你也可以获得被通知方法的返回值。
这个接口返回空。虽然你可以得到目标方法的返回值,但是你不能替换返回值。
③:Around:环绕通知(拦截器)
特点:a:可以改变目标方法执行的结果|b:也可以改变目标方法执行的流程|c:目标方法执行之前,之后均可执行
MethodInterceptor接口
第一:能够控制目标方法是否真的被调用,能过调用MethodInvocation.proceed(),方法来调用目标方法;
第二:MethodInterceptor让你可以控制返回的对象,就是说你可以返回一个与proceed()方法返回对象完全不同的对象,
但是要谨慎使用,必要时才用。
MethodInterceptor接口
public class SomeServiceInterceptor implements MethodInterceptor{
public Object invoke(MethodInvocation arg0) throws Throwable {
//方法之前的操作
System.out.println(arg0.getMethod().getName() + " execute at:" + new Date());
//执行目标方法
Object rsObj = arg0.proceed();
//方法之后的操作
System.out.println("welcome to use again.");
return rsObj;
}
}
④:After-throwing:异常处理通知,在目标方法抛出异常之后执行,处理异常,异常处理之后会将异常抛给调用者;
ThrowsAdvice(标识接口)
public void afterThrowing(IllegalNameException ine){
System.out.println(ine.getMessage());
}
⑤引入通知:
也是切面(Introduction):动态地为目标类中添加新的方法,属性;引入类中加入 --------》aop7
本质:动态地给一个类提供一个接口和实现
编程:
step1:将新增加的方法放在一个新的接口(IA)中;
step2:写一个引入类需要现实(IA)接口还要现实IntroductionInterceptor接口(这个接口中去判断);
step3:配置引入;
——————————————————————————————————————————————————
((IOtherService)service).doOther();
public class MyIntroductionInterceptor implements IOtherService,IntroductionInterceptor{
@Override
public void doOther() {
// TODO Auto-generated method stub
System.out.println("doOther()...");
}
@Override
public Object invoke(MethodInvocation arg0) throws Throwable {
if(implementsInterface(arg0.getMethod().getDeclaringClass())){
return arg0.getMethod().invoke(this, arg0.getArguments());
}
return arg0;
}
@Override
public boolean implementsInterface(Class intf) {
//这个方法的含义是判断调用类型是否是参数类型或者其父类型
//比如
//ArrayList.class.isAssignableFrom(ArrayList.class) true
return intf.isAssignableFrom(IOtherService.class);
}
}
——————————————————————————————————————————————————
<bean id="someServiceTarget" class="aop7.SomeServiceImpl"/>
<bean id="myIntro" class="aop7.MyIntroductionInterceptor"/>
<bean id="myIntroAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
<constructor-arg>
<value>aop7.IOtherService</value>
</constructor-arg>
<constructor-arg>
<ref local="myIntro"/>
</constructor-arg>
</bean>
<!-- 如果目标类没有实现任何接口,在使用引入时,一定要设置proxyTargetClass=true -->
<bean id="someService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="aop7.ISomeService"/>
<property name="target" ref="someServiceTarget"/>
<property name="interceptorNames">
<list>
<value>myIntroAdvisor</value>
</list>
</property>
</bean>
——————————————————————————————————————————————————
一个类实现了两个接口怎么办?
<!-- 代理类实现的接口,写法>
<property name="proxyInterfaces">
<list>
<value></value>
<value></value>
</list>
</property>
方法这样执行:((OtherService)service).doOther();
3:切入点: Advisor= Advice(切面:交叉业务逻辑) + Pointcut(织入的位置)
默认情况下,切面会织入到所有的方法之上;
◆自定义切入点:Pointcut接口 :
ClassFilter接口__getClassFilter()如何选择目标类:
ClassFilter一个方法matches(Class clazz目标对象所对应的class对象) 返回boolean
MethodMatcher接口__getMethodMatcher():
MethodMatcher:三个方法
a:boolean isRuntime()
false:是一个静态切入点(依据方法的静态特征<方法名>)
true:这个切入点是一个动态切入点c方法才会执行了
b:matches(Method method目标方法,Class targetClass) method.getName()可以做出选择return true/false;
c:matches(Method method目标方法,Class targetClass,Object[] args方法的参数)
动态切入点耗时间性能低,可依据参数选择是否用切入点
PointcutAdvisor接口:
<!-- step1 配置目标对象 -->
<bean id="someServiceTarget" class="aop5.SomeServiceImpl"/>
<!--
step2:配置切面
-->
<bean id="logAdvice" class="aop5.LogAdvice"/>
<bean id="myPointcut" class="aop5.MyPointcut"/>
<bean id="logAdvisor" class="aop5.LogAdvisor">
<property name="advice" ref="logAdvice"/>
<property name="pointcut" ref="myPointcut"/>
</bean>
<!--
step3:配置代理
-->
<bean id="someService" class="org.springframework.aop.framework.ProxyFactoryBean">--------这个类一次只能为一个目标对象配置代理
<!-- 代理类实现的接口,如果没有实现接口,则不用配置 -->
<property name="proxyInterfaces" value="aop5.ISomeService"/>
<!-- 目标对象 -->
<property name="target" ref="someServiceTarget"/>
<!-- 切面-->
<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
</bean>
——————————————————————————————————————————————————————————————
◆系统预定义的切入点
NameMatchMethodPointcutAdvisor:
setMappedName(String)方法名
setClassFilter(ClassFilter)目标类选择
<!-- step1 配置目标对象 -->
<bean id="someServiceTarget" class="aop6.SomeServiceImpl"/>
<!--
step2:配置切面
-->
<bean id="logAdvice" class="aop6.LogAdvice"/>
<bean id="logAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="logAdvice"/>
<property name="mappedNames">
<list>
<value>do*</value> --------->以do开头的所有方法
</list>
</property>
</bean>
<!--
step3:配置代理
-->
<bean id="someService" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理类实现的接口,如果没有实现接口,则不用配置 -->
<property name="proxyInterfaces" value="aop6.ISomeService"/>
<!-- 目标对象 -->
<property name="target" ref="someServiceTarget"/>
<!-- 切面-->
<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
</bean>
规则表达式切入点:RegexpMethodPointcut:具体看图片
======================================================================================================================================================================
======================================================================================================================================================================
4:自动配置代理--------一次性为多个目标对象配置代理;
①:依据Bean的名字(ID)
BeanNameAutoProxyCreator:后处理Bean
void setBeanNames(String[] beanNames) :用来指定需要指定的目标对象
<property name="beanNames">
<list>
void setInterceptorNames(String[] interceptorNames):将切面指定
<bean id="someService" class="aop8.SomeServiceImpl"/>
<bean id="otherService" class="aop8.OtherServiceImpl"/>
<bean id="logAdvice" class="aop8.LogAdvice"/>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>someService</value>
<value>otherService</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>logAdvice</value>
</list>
</property>
</bean>
——————————————————————————————————————————————————
②:依据Advisor与目标对象自动匹配
DefaultAdvisorAutoProxyCreator:将所有的Advisor与目标对象匹配,生成代理,要求切面必须是一个Advisor
<bean id="someService" class="aop9.SomeServiceImpl" />
<bean id="otherService" class="aop9.OtherServiceImpl" />
<bean id="logAdvice" class="aop9.LogAdvice" />
<bean id="logAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedNames">
<list>
<value>doSome</value>
<value>doOther</value>
</list>
</property>
<property name="advice" ref="logAdvice"/>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
</bean>
——————————————————————————————————————————————————
5:使用标注与切入点表达式来进行AOP的编程--------》aop10
以上是基于接口使用AOP,现在通过标注使用AOP:借的是AspectJ(AOP框架);
编程:
step1:引入AspectJ相关的库
step2:编写切面类:(是一个POJO类)
a:类前用@Aspect :加在切面类之前 ,标识这是一个切面
b:编写通知(交叉业务逻辑:通过方法)并且添加标注(@Before|)以及切入点表达式(比如 execution(x doSome(...)):在方法前)
c:配置代理:
①:自动配置代理
②:使用schema元素来自动配置代理
--------------------------------------------------------------------------------------------------------
@Aspect :加在切面类之前 ,标识这是一个切面
@Before(切入点表达式):前置通知
@AfterReturning:后置通知
@AfterThrowing:异常处理通知
@After:在目标方法执行完毕或者发生异常之后被调用
@Around:环绕通知
@DeclareParents引入 Introduction
--------------------------------------------------------------------------------------------------------
切入点表达式(Pointcut expressions)8种:
execution:
execution(方法修饰符<可选> 返回类型<必须是*号是任意的返回类型> 方法名(参数<可选:是..时任意,参数类型如果是java.lang中类型不必写上包名,其它要写>)) );
--------------------------------------------------------------------------------------------------------
<aop:aspectj-autoproxy>:指示spring容器,自动配置代理
a:导入AOP命名空间
b:在配置文件当中,添加标注
--------------------------------------------------------------------------------------------------------
@Aspect
public class BankServiceAspect {
@Before("execution(* openAccount(..))")
public void log(JoinPoint jp){
System.out.println(jp.getSignature().getName()+" execute at: "+new Date());
}
@AfterReturning(value="execution(* withdraw(..))",returning="retVal")//asm参数名绑定
public void welcome(JoinPoint jp,double retVal){
//获得目标方法的返回结果
if(retVal>10000)
System.out.println("请提前预约!");
System.out.println("welcome to use again.");
}
@Around("execution(* openAccount(..))")
public Object transationManage(ProceedingJoinPoint pjp) throws Throwable{//ProceedingJoinPoint这个接口来调用目标方法
System.out.println("Begin Transaction...");
Object rsObj=null;
try{
rsObj=pjp.proceed();//这个异常要抛出去
}catch(Exception e){
System.out.println("Rollback Transaction...");
throw e;
}
System.out.println("Commit Transaction...");
return rsObj;
}
@AfterThrowing(value="execution(* deposite(..))",throwing="bae")//参数名绑定bae这个对象在下面才可以获得
public void exceptionHandler(JoinPoint jp,BankAppException bae){
System.out.println(bae.getMessage());
}
@DeclareParents(value="aop10.BankServiceImpl",defaultImpl=aop10.StockService.class)
public IStockService stockService;
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:aspectj-autoproxy/>
<bean id="bankService" class="aop10.BankServiceImpl"/>
<bean class="aop10.BankServiceAspect" />
</beans>
--------------------------------------------------------------------------------------------------------
引入:
a:定义新的接口,添加新的方法
b:写一个pojo类实现新的接口
c:
======================================================================================================================================================================
======================================================================================================================================================================
Spring对持久层的支持:
模板方法(“开闭原则”模式):
模版类的作用:
①:封装了业务流程(不变);
②:可以事先确定的业务先实现,可以被共享;
③:将变化的部分留给子类来实现;
一:Spring对持久层支持采取的“策略”:
①:采用DAO模式(目的将具体的持久层技术与业务层解耦)
②:采用模版方法来简化具体持久层技术的使用
Ⅰ:资源的管理<比如Connection session的获取与关闭>
Ⅱ:异常的处理(重新定义了一套异常类----运行时异常,提供异常的具体细节)
Ⅲ:事务的管理
③:使用IOC来解耦持久层与业务层
二:编程:
㈠:spring对JDBC支持:
step1:配置DataSource: (a:使用应用服务器提供的数据源|b:使用单独的产品:比如Apache(BasicDatasource),spring的Drivermanager(学习))
//step2:配置模版类(JdbcTemplate),Datasource注入
step2:配置DAO,继承JdbcDaoSupport模版注入
step3:配置Service,DAO注入
————————————————————————————————————————————————————
重要使用:
private JdbcTemplate jt;
Object[] params= new Object[]{c.getId()};
jt.update(sql,params);
findByName(): return (Customer) jt.queryForObject(sql, params,new CustomerRowMapper());
findAll(): return jt.query(sql, new CustomerRowMapper());
public class CustomerRowMapper implements RowMapper{}(使用RowMapper定义如何将ResultSet变成java对象)
@Override
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Customer c = new Customer();
c.setId(rs.getLong("id"));
c.setName(rs.getString("name"));
c.setAge(rs.getInt("age"));
return c;
}
————————————————————————————————————————————————————
配置文件:
<!-- DataSource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/tarena</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>LWSX</value>
</property>
</bean>
<!-- JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- DAO -->
<bean id="customerDAO" class="dao.impl.CustomerDAOJdbcImpl">
<property name="jt" ref="jdbcTemplate" />
</bean>
<!-- Service -->
<bean id="customerService" class="service.impl.CustomerServiceSpringImpl">
<property name="customerDAO" ref="customerDAO" />
</bean>
————————————————————————————————————————————————————
======================================================================================================================================================================
======================================================================================================================================================================
㈡:spring对Hibernate支持:
step1:配置DataSource
step2:配置SessionFactory
step3:配置DAO 继承HibernateDaoSupport
step4:配置service
使用第三方的数据源:
a:将jar文件加入到classpath
b:配置
————————————————————————————————————————————————————
重要使用:
public class CustomerDAOHibernateImpl extends HibernateDaoSupport implements CustomerDAO{
@Override
public void delete(Customer c) {
// TODO Auto-generated method stub
getHibernateTemplate().delete(c);
}
@Override
public void delete(String name) {
// TODO Auto-generated method stub
Customer c = findByName(name);
getHibernateTemplate().delete(c);
}
@Override
public List<Customer> findAll() {
// TODO Auto-generated method stub
return getHibernateTemplate().find("from Customer c");
}
@Override
public Customer findByName(final String name) {
// TODO Auto-generated method stub
//有多个可以参数使用数组
//return (Customer)getHibernateTemplate().findByNamedParam("from Customer c where c.name=:n", "n", name).get(0);
//使用HibernateCallback方式:即可以获得模版类的管理资源的好处,又可以按照熟悉的Hibernate的API来编程
HibernateTemplate template = getHibernateTemplate();
return (Customer) template.execute(new HibernateCallback(){
@Override
public Object doInHibernate(Session session)throws HibernateException, SQLException {
String hql="from Customer c where c.name=:n";
return session.createQuery(hql).setString("n", name).uniqueResult();
}
});
}
@Override
public void modify(Customer c) {
// TODO Auto-generated method stub
getHibernateTemplate().merge(c);
}
@Override
public void save(Customer cust) {
// TODO Auto-generated method stub
//模版类是线程安全的
getHibernateTemplate().save(cust);
}
}
————————————————————————————————————————————————————
配置文件:
<!-- DataSource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/tarena</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>LWSX</value>
</property>
</bean>
<!-- SessionFactory -->
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="mappingResources">
<list>
<value>entity.\Customer.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
</props>
</property>
</bean>
<!-- DAO -->
<bean id="customerDAO" class="dao.impl.CustomerDAOHibernateImpl">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<!-- Service -->
<bean id="customerService" class="service.impl.CustomerServiceSpringImpl">
<property name="customerDAO" ref="customerDAO"/>
</bean>
————————————————————————————————————————————————————
======================================================================================================================================================================
======================================================================================================================================================================
Spring对事件的支持:spring_transaction
事务当作一个切面,动态地织入到目标对象,形成一个代理对象。
①事务概念:事务可以保证一系列的操作可以作为一个工作单元来执行机制;
②事务特性:
Ⅰ:事务的传播行为(客户端发起的事务,如何影响被调用者的事务Bean类)
七个:(7种=EJB 的 6 种传播行为+嵌套式事务
PROPAGATION_REQUIRED(有则用,无容器提供)一般用于数据的写操作
PROPAGATION_SUPPORTS(有则用,没有不提供)一般用于数据的读操作
PROPAGATION_REQUIRES_NEW(客户端有挂起,Bean建一个|客户端没有,Bean还是建一个)
嵌入式事务:一个事务由多个子工作单元组成,每一个子工作单元都可以单独回滚;SAVEPOINT
Spring 对事务的边界多了一种嵌套事务(PROPAGATION_NESTED)。
PROPAGATION_NESTED:
如果客户端启动了事务 T1,那么 Bean 启动一个嵌套在 T1中的子事务 T2;
如果客户端没有启动事务,那么 Bean 会启动一个新的事务,类似于REQUIRED_NEW
Ⅱ:隔离性
Ⅲ:只读事务(可以对查询操作优化)
Ⅳ:事务的超时
Ⅴ:回滚规则:
运行时异常,回滚|受查,提交|默认
受查异常要用:设置:+异常类型,提交
-异常类型,回滚
Spring 的容器对于非受查异常(服务模块中抛出的非受查异常),会回滚事务。对于受查异常,会提交事务。
如果即使发生了某种受查异常,也要回滚事务,可以用 “- 异常类型“来声明。同样,对于非受查异常,如果不要求回滚事务,可以用"+异常类型"来声明。
-------------------------------------------------------------------------------------------------------------------------------------
<一>:采取策略:
1:采用一致的编程模型来处理事务
a:本地事务:只涉及到一个数据资源。分布式事务:一个事务涉及到多个数据资源。都可以来用相同的方式来编程;
b:使用事务管理器,来将应用程序与底层容器具体的事务机制解耦PlatformTransactionManager接口:
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
实现:
DataSourceTransactionManager
HibernateTransactionManager
JdoTransactionManager
JtaTransactionManager
2:声明:对持声明式的事务,通过配置文件/标注来声明事务特性;|spring通过AOP的方式来将事务作为一个切面注入到业务对象当中的;
3:分布式:spring对分布式事务的支持,分布式事务如何实现:通过事务管理器JTA,它通过两个阶段提交协议管理:提交准备:询问|提交:提交;
a:在容器外使用:(不使用应用服务器,比如:weblogic,jboss)使用支持分布式事务的事务管理器(JTATransactionManager);比如“JOTM”产品;
b:在容器内使用:直接使用容器提供的分布式事务的支持;
spring用工具看spring.xml结构
-------------------------------------------------------------------------------------------------------------------------------------
<二>:spring对Hibernate事务的支持:
⑴:采用接口:
步骤:
step1:DataSource
step2:SessionFactory
step3:配置事务管理器
step4:DAO
step5:配置目标对象(业务层中的对象)
step6:配置事务代理
配置文件:_______________________________________________________________________________________
<!-- DataSource -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/tarena</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>LWSX</value>
</property>
</bean>
<!-- SessionFactory -->
<bean id="mySessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="mappingResources">
<list>
<value>entity\Account.hbm.xml</value>
<value>entity\Stock.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- 配置事务管理器 -->
<bean id="myTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<!-- Dao -->
<bean id="abstractDAO" abstract="true">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<bean id="accountDAO" class="dao.impl.AccountDAOHibernateImpl" parent="abstractDAO"/>
<bean id="stockDAO" class="dao.impl.StockDAOHibernateImpl" parent="abstractDAO"/>
<!-- Service target-->
<bean id="transferServiceTarget" class="service.impl.TransferServiceSpringImpl">
<property name="accountDAO" ref="accountDAO"/>
<property name="stockDAO" ref="stockDAO"/>
</bean>
<!-- 配置事务代理 -->
<bean id="transferService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target" ref="transferServiceTarget"/>
<property name="transactionManager" ref="myTransactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="open*">PROPAGATION_REQUIRED</prop>
<prop key="query*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="transfer">PROPAGATION_REQUIRED,-TransferException</prop>
</props>
</property>
</bean>
_______________________________________________________________________________________
⑵:spring中使用标注来添加事务管理:
步骤:
1:之前要引入tx命名空间,指示spring容器使用标注来提供事务切面:其中去找一下
2:在业务对象当中添加@Transactional来声明事务切面(方法前面)
step1: DataSource
step2: SessionFactory
step3: HibernaterTransactionManager
step4: DAO
step5: Service
配置文件:_______________________________________________________________________________________
<!-- DataSource -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/tarena</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>1234</value>
</property>
</bean>
<!-- SessionFactory -->
<bean id="mySessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="mappingResources">
<list>
<value>entity\Account.hbm.xml</value>
<value>entity\Stock.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- 配置事务管理器 -->
<bean id="myTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<!-- Dao -->
<bean id="abstractDAO" abstract="true">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<bean id="accountDAO" class="dao.impl.AccountDAOHibernateImpl" parent="abstractDAO"/>
<bean id="stockDAO" class="dao.impl.StockDAOHibernateImpl" parent="abstractDAO"/>
<!-- Service-->
<bean id="transferService" class="service.impl.TransferServiceSpringImpl2">
<property name="accountDAO" ref="accountDAO"/>
<property name="stockDAO" ref="stockDAO"/>
</bean>
<tx:annotation-driven transaction-manager="myTransactionManager"/>
_______________________________________________________________________________________
类的用法:_______________________________________________________________________________________
@Transactional(propagation=Propagation.REQUIRED)
public void openAccount(String name, double balance) {}
@Transactional(propagation=Propagation.REQUIRED)
public void openStock(String name) {}
@Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
public double queryBalance(String accName) {}
@Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
public double queryQty(String stockName) {}
@Transactional(propagation=Propagation.REQUIRED,rollbackFor=TransferException.class)
public void transfer(String accName, String stockName, double amt) throws TransferException{}
_______________________________________________________________________________________
-------------------------------------------------------------------------------------------------------------------------------------
<三>:spring对JDBC事务的支持:(同上)
a:基于配置文件:
1:DataSource
2:事务管理器DataSourceTransactionManager
3:DAO
4:配置目标对象
5:配置事务代理TransactionProxyFactoryBean
b:基于标注方式:
1:DataSource
2:事务管理器DataSourceTransactionManager
3:DAO
4:配置目标对象service
5:之前要引入tx命名空间,指示spring容器使用标注来提供事务切面|在业务对象当中添加@Transactional来声明事务切面(方法前面)
-------------------------------------------------------------------------------------------------------------------------------------
======================================================================================================================================================================
======================================================================================================================================================================
Spring当中支持分布式事务:
A:应用不在应用服务器(weblogic ,jboss, was)当中运行------》spring_transaction3
step1:选择一个支持JTA事务能力的事务管理器(weblogic ,jboss, was,JOTM:java open transaction manager开源应用服务器的一部分)
step2:将JOTM相关的jar文件加入classpath,并且提供相关的配置文件
step3:在Spring中配置JOTM:
①:DataSource必须要支持分布式事务“XADataSource”,JDBC驱动也要支持
②:事务管理器用:JTATransactionManager
③:配置JOTM
B:就用在应用服务器当中运行:spring可以将分布式事务交给应用服务器
-------------------------------------------------------------------------------------------------------------------------------------
Spring对Struts的对持:
Struts(表示层)+Spring(中间层:业务层,持久层)+Hibernate(数据库):SSH<--------->Jsp+servlet+EJB:JSE
一:集成的方式:
1:要解决的问题:
①:web应用怎么样获得spring容器的引用
可以使用Listener/plugin加载spring的代码
②:Action如何获得被spring容器管理的Bean
用getBean()/IOC的方式
③:集成:
使用ActionSupport(spring提供的):getWebApplicationContext()可以获得spring的引用
step1:加载spring:Listener:web.xml/plugin:struts.xml方式加载 配置文件路径默认从根目录下搜索的
step2:就用中的Action继承ActionSupport
step3:调用getWebApplicationContext()获得容器的引用
二:编程:
1:web获得spring容器引用:spring_struts工程
直接继承ActionSupport
优点:不影响struts原有编程风格简单
缺点:struts依据spring,作“IOC”方式倡导不符