Spring学习笔记3Word文档格式.docx
《Spring学习笔记3Word文档格式.docx》由会员分享,可在线阅读,更多相关《Spring学习笔记3Word文档格式.docx(29页珍藏版)》请在冰豆网上搜索。
Proxyproxy=newProxy(landlord);
proxy.rent();
}
1.1.代理对象特征
1.实现和被代理者相同的接口(房东的接口)
2.代替目标对象完成相应的功能。
3.目标方法完成之后,会完成额外的操作。
2.静态代理
场景设计
我们的数据库操作需要事务的控制,addupdatedel等方法都需要添加事务。
例子:
发现问题:
在Servic代码的分离。
1.实现和被代理者相同的接口
2.注入需要的属性
目标对象中的代码只处理业务相关的工作,实现了代码的分离
代理类中的代码:
代理类中的代码
静态代理模式
缺点:
1、一个service对应一个代理类,那么100个service对应100个代理类
2、代理类的每一个方法中都需要填写事务的开启和事务的提交,复用性不高
3、代理类不具备通用性
3.动态代理
3.1.动态代理的种类:
3.2.动态代理的实现
publicclassBeanFactoryProxy{
publicstaticObjectgetProxy(finalObjecttarget,finalTransactionManagertx){
Objectproxy=Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),
newInvocationHandler(){
@Override
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
throwsThrowable{
Objectresult=null;
StringmethodName=method.getName();
//对于需要添加事务的代码认为进行控制
if(methodName.equals("
add"
)||methodName.equals("
del"
update"
)){
try{
tx.begin();
result=method.invoke(target,args);
mit();
}catch(Exceptione){
tx.rollback();
}
}else{
//不需要添加事务的代码直接执行
result=method.invoke(target,args);
}
returnresult;
}
});
returnproxy;
测试代码:
@Test
publicvoidtest01(){
ApplicationContextcontext=newClassPathXmlApplicationContext("
applicationContext.xml"
//得到目标对象
UserServicetarget=(UserService)context.getBean("
target"
//得到事务对象用来做事务操作
TransactionManagertx=(TransactionManager)context.getBean("
tx"
//得到代理对象
UserServiceuserService=(UserService)BeanFactoryProxy.getProxy(target,tx);
//查看对象的类型
System.out.println(userService.getClass());
userService.find();
动态代理模式优缺点:
优点:
1.实现了代码的分离
2.实现了代码的重复利用,原来每个方法上都需要添加事务,现在只需添加一遍。
缺点:
1.只能处理事务,不具有通用性(日志,安全,权限)
2.使用jdk的动态代理必须实现接口,否则不能生成代理对象。
3.目标类的每个方法都经过判断降低性能。
3.3.Cglib动态代理
不需要实现接口也可以生成代理对象,并且代理对象是目标类的子类
publicclassBeanFactoryProxy{
//第一步:
创建增强器对象
Enhancerenhancer=newEnhancer();
//第二步:
注入目标类的接口
//enhancer.setInterfaces(target.getClass().getInterfaces());
//第三步:
设置父类(目标对象)
enhancer.setSuperclass(target.getClass());
//第四步:
enhancer.setCallback(newMethodInterceptor(){
@Override
publicObjectintercept(Objectproxy,Methodmethod,Object[]args,
MethodProxymethodProxy)throwsThrowable{
Objectresult=null;
try{
tx.begin();
method.invoke(target,args);
mit();
}catch(Exceptione){
e.printStackTrace();
tx.rollback();
}
returnresult;
}
});
returnenhancer.create();
4.Spring生成代理对象
说明:
Spring也整合了代理模式
JDK代理实现的接口InvocationHandler
CGLIB代理实现的接口是MethodInterceptor
所以Spring为了代码的服用也进行了接口的抽象MethodInterceptor
是aopalliance.jar这个包下的,spring实现该接口可以自由切换代理模式。
springProxyBean代码如下
//这是一个事物的通知类
publicclassSpringTransactionProxyimplementsMethodInterceptor{
privateTransactionManagertx;
publicvoidsetTx(TransactionManagertx){
this.tx=tx;
publicObjectinvoke(MethodInvocationmethod)throwsThrowable{
try{
tx.begin();
method.proceed();
//如果有下一个通知,继续执行通知,如果没有通知,就会执行目标方法
mit();
}catch(Exceptione){
tx.rollback();
}
returnnull;
配置文件
<
!
--配置目标类-->
beanid="
userDao"
class="
dao.UserDaoImpl"
>
<
/bean>
service.UserServiceImpl"
<
propertyname="
ref="
/property>
--配置通知类-->
transaction.TransactionManager"
txAdvice"
advice.SpringTransactionProxy"
--配置用来产生代理对象的工厂默认使用jdk的代理模式-->
userService"
org.springframework.aop.framework.ProxyFactoryBean"
--1.指明代理需要实现的接口-->
interfaces"
<
list>
<
value>
service.UserService<
/value>
/list>
--2.指明一个目标类-->
targetName"
value="
--<
-->
--3.指名通知类-->
interceptorNames"
txAdvice<
--切换代理模式
proxyTargetClass默认为falsejdk代理模式
proxyTargetClasstruecglib代理模式
-->
proxyTargetClass"
true"
Spring代理工厂的缺点
1.目标陪如果有多个,就会有多个代理类,每个代理类都要重新配置,给配置文件带来了麻烦。
Spring2.5以后就解决的这样的问题
5.SpringAOP面向切面编程
5.1.名词解释
5.1.1.切面(Aspect)
用来完成某些特定功能的类(例如事务处理的类)
切面包括:
日志,安全性处理的类,权限控制,系统中抽象的通用的类。
5.1.2.连接点(JoinPoint):
客户端调用的方法。
5.1.3.通知(Advice):
完成某些特定功能的方法就是通知
5.1.4.切入点(PointCut):
If判断条件就是切入点,只有满足切入点,切面才有效,并且通知和目标方法相结合。
5.1.5.目标对象(Target):
正真执行目标方法的类
5.1.6.AOP代理对象(Proxy)
客户端调用都是代理对象
代理对象:
1.jdk的动态代理,要求必须实现接口。
2.cglib的动态代理,不需要实现接口,并且代理对象是目标对象的子类。
5.1.7.织入(Wearing):
代理对象的方法体,用来连接通知和目标对象。
5.2.通知的概念
1.前置通知:
目标方法之前执行的通知接口MehtodInterc
2.后置通知:
目标方法之后执行的通知
3.异常通知:
目标方法抛出异常后执行的通知
4.最终通知:
切面最后执行的通知(必然会执行finally)。
5.环绕通知:
目标方法执行前后执行的通知。
5.3.AOP实现
实现步骤:
1.导入相关jar包
2.编写配置文件的头(导入schema约束)
3.编写目标类
4.编写切面和通知
5.配置切入点表达式
6.配置xml配置文件(关联切面)
5.3.1.导入相关jar包
一共5个jar包
前两个是和Spring整合的jar包,spring依赖第三方的三个jar包。
spring-aop.jar
spring-aspects.jar
aopalliance.jar
aspectjrt.jar
aspectjweaver.jar
5.3.2.AOP配置文件头
?
xmlversion="
1.0"
encoding="
UTF-8"
beansxmlns="
http:
//www.springframework.org/schema/beans"
xmlns:
context="
//www.springframework.org/schema/context"
util="
//www.springframework.org/schema/util"
aop="
//www.springframework.org/schema/aop"
xsi="
//www.w3.org/2001/XMLSchema-instance"
xsi:
schemaLocation=
"
//www.springframework.org/schema/beans
http:
//www.springframework.org/schema/beans/spring-beans-3.2.xsd
//www.springframework.org/schema/context
//www.springframework.org/schema/context/spring-context-3.2.xsd
//www.springframework.org/schema/util
//www.springframework.org/schema/util/spring-util-3.2.xsd
//www.springframework.org/schema/aop
//www.springframework.org/schema/aop/spring-aop-3.2.xsd"
/beans>
5.3.3.添加schema约束
配置方法和之前的相同
5.3.4.编写目标类
publicclassOrderServiceImplimplementsOrderService{
privateOrderDaoorderDao;
publicvoidsetOrderDao(OrderDaoorderDao){
this.orderDao=orderDao;
@Override
publicvoidadd(){
orderDao.add();
publicvoiddel(){
orderDao.del();
publicvoidupdate(){
orderDao.update();
publicvoidfind(){
orderDao.find();
目标类2
publicclassUserServiceImplimplementsUserService{
privateUserDaouserDao;
publicvoidsetUserDao(UserDaouserDao){
this.userDao=userDao;
userDao.add();
userDao.del();
userDao.update();
userDao.find();
5.3.5.编写切面和通知
开关事物具体代码
publicclassTransactionManager{
publicvoidbegin(){
事物开始"
publicvoidcommit(){
事物提交"
publicvoidrollback(){
事物回滚"
通知类具体编辑代码
publicclassTxAdviceimplementsMethodInterceptor{
publicObjectinvoke(MethodInvocationmi)throwsThrowable{
mi.proceed();
5.3.6.切入点表达式
aop:
pointcutexpression="
within(service.*)"
id="
txPointcut"
/>
Within()表达式只能匹配到类级别
Within(包名.类名)只匹配包下的一个类
Within(包名.*)匹配包下的所有类(不包括子包下的)
Within(service..*)匹配这个包下的所有类,包括子孙包
Execution()表达式能匹配到方法级别(具体到方法)
execution(返回值包名.类名.方法(参数类型))
例子1:
pointcutexpression=
"
execution(intservice.UserServiceImpl.add())"
改切点表达式表示
返回值为int包名类名serviceUserServiceImpl方法为add()的匹配规则
例子2:
execution(*service.*.add())"
规则:
返回值值任意,包名service下子类的add(),只能包含一层,子孙类不行。
例子3:
pointcut
expression="
execution(*service..*.add())"
方法返回值任意,service包下的所有子孙类的add()
例子4:
execution(*service..*.add(int,String))"
返回值的类型任意service子孙包下的add方法参数类型为int,String
execution(*service..*.add(..))"
id="
返回值类型任意service下的所有子孙类.add方法()(参数任意)
5.3.7.配置xml配置文件
--1.配置目标类-->
orderDao"
dao.OrderDaoImpl"
orderService"
service.OrderServiceImpl"
--2.配置通知类-->
advice.TxAdvice"
prope