动态代理
JDK的动态代理模式:
场景设计:通过动态代理模式实现事务控制
动态代理代码:
JDK的动态代理:
1.能够实现代码的松耦合,并且能够解决代码重复性的问题。
2.需要被代理者必须实现接口
3.动态代理模式只能处理一类业务,如果处理业务不同,需要重新编写动态代理。
cglib动态代理模式:
使用cglib动态代理模式,即使被代理者没有实现接口,也可以为其创建代理对象。
创建代理对象的步骤:
说明:cglib创建的代理对象,底层通过二进制码的形式创建,并且生成的代理对象都是目标对象的子类,并且有无接口都可以生成代理对象。
cglib和jdk的区别:
jdk创建代理对象的速度较快,cglib创建代理对象的速度较慢
jdk的动态代理需要实现----InvocationHandler接口
SpringAOP的名称介绍:
切面(Aspect):完成特定功能的类, 能够在目标方法前后做一些额外操作。就是一个切面,
连接点(Joinpoint):客户端调用的某个特定的方法,就是接口中的方法。
通知(Advice):就是切面中的方法(额外的工作),切面类中的方法就是通知。
切入点(Pointcut):(就是一种匹配规则)-----就是在invoke方法中,满足该切入点才能将通知与目标方法结合在一起。在使用目标方法前,进行某些判断(例如if-else ),符合判断中的条件才能将通知与目标方法结合在一起。
目标对象(Target Object):真正调用方法的对象,就是真正要使用的那个方法的对象。就是委托类的对象。
AOP编程:
场景设计:要使用AOP完成事物控制
步骤:
1.导入jar包,导入5个jar包
2:定义切面和通知
3.编写配置文件
配置顺序
说明:该配置顺序不能跌倒,如果其中某一项不需要配置,直接写下一项
AOP的执行原理:
当一个对象执行前先会与切入点表达式进行匹配,如果匹配成功了,就会为这个类创建代理对象(通过动态代理模式创建如果目标对象有接口就使用jdk的动态代理,如果目标对象没有接口则使用cglib生成代理对象),代理对象执行方法时就会执行切面中的通知。
切入点表达式:
1-within() 按类进行匹配控制的粒度比较粗
Within(包名.类名)
1.within(cn.service.UserServiceImpl) 只能匹配UserServiceImpl这个类
2.within(cn.service.*) 匹配当前包下的全部类(一层)
3.within(cn.service..*) 匹配当前包下的全部子孙包
2-execution() 控制的粒度较细,能够控制到方法和参数级别
execution(建议使用)(返回值类型包名.类名.方法名(参数类型))
(*)所有子类----只能包含一层,只能表示某包下面的所有子类,孙类不行。
(.*)所有子孙类----包含多层,表示某包下面的所有子孙类。(..)任意的----方法类型
案例:
例子1:<aop:pointcut expression=“execution(int service.UserServiceImpl.add())" id="txPointcut"/>
该切点表达式表示:返回值为int 包名类名serviceUserServiceImpl 方法为add()的匹配规则
例子2:<aop:pointcutexpression="execution(* service.*.add())" id="txPointcut"/>
规则:返回值值任意,包名service下子类的add(),只能包含一层,子孙类不行。
例子3:<aop:pointcut expression="execution(* service..*.add())" id="txPointcut"/>
规则:方法返回值任意, service包下的所有子孙类的add()
例子4:<aop:pointcut expression="execution(* service..*.add(int,String))" id="txPointcut"/>
规则:返回值的类型任意 service子孙包下的add方法参数类型为int,String
例子5:<aop:pointcut expression="execution(* service..*.add(..))" id="txPointcut"/>
规则:返回值类型任意 service下的所有子孙类.add方法() (参数任意)
AOP中的通知类型:
1.前置通知:在执行目标方法以前调用通知 MethodBeforeAdvice 接口2.后置通知:在执行目标方法以后调用通知 AfterReturningAdvice 接口
3.异常通知:在执行目标方法执行时,出现异常后调用通知 ThrowsAdvice接口方法固定(afterThrowing)
4.环绕通知:在目标方法前后都会调用通知 MethodInterceptor接口
说明:
异常后通知可能告知 异常是什么,但是不能够处理。
环绕通知中可以对异常进行处理,功能比较强大。
5:通知中的参数:参数应该放在第一位,否则报错
环绕通知中的参数使用的是:ProceedingJoinPoint
其他的都使用:joinPoint
joinPoint.proceed() 作用有两个
1.如果有下一个通知,就执行下一个通知,
2.如果没有下一个通知则执行目标方法。
<aop:advisor advice-ref="initAdvice" pointcut-ref="txPointcut" order="10"/>
<aop:advisor advice-ref="initAdvice2" pointcut-ref="txPointcut" order="1"/>
通知执行的顺序 可以通过order属性来控制:
前置通知中 数字越小 越先执行 1 先执行
后置通知中 数字越大 越先执行 10先执行
通知中的参数
1-除了环绕通知之外,其余的通知全部使用import org.aspectj.lang.JoinPoint;
而环绕通知使用的是import org.aspectj.lang.ProceedingJoinPoint;
规定:如果通知中有多个参数,JoinPoint或.ProceedingJoinPoint必须位于参数的第一位否则报错
2-配置文件中的返回参数应该与通知中的参数一致
后置通知返回值问题:
Returning="number" 表示目标方法执行后的返回值
通知中必须要包含返回值,并且名称相同
异常通知:
通知的执行规则:
1.当异常通知执行时,后置通知将不会执行。异常通知和后置通知(after-return)是互斥的。
2.最终通知无论如何都会被执行。
3.当目标方法执行时出现异常时,环绕通知的后半部分将不会被执行。
4.当环绕通知遇到后置通知时,如果后置通知想得到返回值,那么环绕通知必须添加return 将返回值返回
5.当多个环绕通知同时执行时,其执行顺序是嵌套结构
joinPoint.proceed() 作用有两个
1.如果有下一个通知,就执行下一个通知,
2.如果没有下一个通知则执行目标方法。