动态代理
特点:字节码随用随创建,随用随加载
作用:不能修改源码的基础上对方法增强
分类:
基于接口的动态代理
基于子类的动态代理
基于接口的动态代理:
涉及的类:Proxy
提供者:JDK官方
如何创建代理对象:
使用Proxy类中的newProxyInstance方法
创建代理对象的要求:
被代理类最少实现一个接口,如果没有则不能使用。
newProxyInstance 方法的参数:
ClassLoader 类加载器
它是用于加载代理对象字节码的,和被代理对象使用相同的类加载器。固定写法
Class[] 字节码数组
它是用于让代理对象和被代理对象有相同的方法,固定写法
InvocationHandler用于提供增强的代码
它是让我们写如何代理,我们一般都是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
此接口的实现类都是谁用谁写
基于子类的动态代理:
基于子类的动态代理:
涉及的类:Enhancer
提供者:第三方cglib库
如何创建代理对象:
使用Enhancer类中的create方法
创建代理对象的要求:
被代理类不能是最终类,
create方法的参数:
Class:字节码
它是用于指定被代理对象的字节码。固定写法
Callback :用于提供增强的代码
我们一般写的是该接口的子接口的实现类:MethodInterceptor
AOP概念
全称,Aspect Oriented Programing 即:面向切面编程
实现方式
使用动态代理
JoinPoint(连接点):
所谓连接点是指那些被拦截的点,在spring中,这些点指的是方法,应为spring只支持方法类型的连接点
Pointcut(切入点):
所谓切入点是指我们要对哪些JoinPoint进行拦截的定义
Advice(通知/增强):
所谓通知是指拦截到JoinPoint之后所要做的事情就是通知,
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知
Target(目标对象):
代理的目标对象
Weaving(织入):
Aspect(切面):
是切入点和通知的结合
关于代理的选择
基于XML的AOP配置
环境搭建
在执行某个方法时,先执行这个方法
配置步骤
<!-- 配置spring 的Ioc,把service对象配置进来-->
<bean id="accountService" class="com.jd.service.impl.AccountServiceImpl"></bean>
<!-- spring中基于xml的AOP配置步骤
1、把通知Bean交给spring来管理
2、使用aop:config标签表明开始AOP的配置
3、使用aop:aspect标签表明配置切面
id属性:是给切面提供一个唯一标识
ref属性:是指定通知类bean的Id
4、在aop:aspect标签的内部使用对应标签来配置通知的类型
我们现在示例是让printLog方法在切入点方法执行之前执行,所以是前置通知
aop:before :表示配置前置通知
method属性:用于指定Logger类中哪个方法是前置通知
pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
切入点表达式的写法:
关键字:execution(表达式)
表达式:访问修饰符 返回值类型 包名.包名.包名......类名.方法名(参数列表)
标准的表达式写法:public void com.jd.service.impl.AccountServiceImpl.saveAccount()
访问修饰符可以省略
void cmo.jd.service.impl.AccountServiceImpl.savaeAccount()
返回值可以使用通配符,表示任意返回值
* com.jd.service.impl.AccountServiceImpl.saveAccount()
包名可以使用通配符,表示任意包,但是有几级包,就需要写几个*。
* *.*.*.*.AccountServiceImpl.saveAccount()
包名可以使用..表示当前包及其子包
* *..AccountServiceImpl.saveAccount()
类名和方法名都可以使用*来实现通配
* *..*.*()
参数列表:
可以直接写数据类型
基本数据类型直接写名称 int
引用类型写包名.类名的方式 java.lang.String
可以使用通配符表示任意类型,但是必须有参数
全通配写法:
* *..*.*(..)
实际开发中切入点表达式的通用写法:
切到业务层实现类
* com.jd.service.impl.*.*(..)
加入的依赖里有个aspectweaver 这个包,作用就是解析出来我们这个切入点表达式
配置切入点表达式,id属性用于指定表达式唯一的标识,此标签如果放在切面标签里 ,要放在最上面,因为约束是这么要求的
<aop:pointcut id="pt1" expression></aop:poincut>
-->
<!--配置Logger类-->
<bean id="logger" class="com.jd.utils.Logger"></bean>
<!---配置AOP->
<aop:config>
<aop:aspect id="logAdvice" ref="logger" >
<aop:before method="printLog" pointcut="execution(public void com.jd.service.impl.AccountServiceImpl.saveAccount())">
</aop:before>
</aop:aspect>
</aop:config>
切点表达式说明
环绕通知
基于注解的AOP配置
环境搭建
配置步骤
环绕通知和注解配置
切入点表达式注解
不使用XML的配置方式