AOP概述
1.AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
2. 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
3.AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
经典应用:事务管理、性能监视、安全检查、缓存 、日志等
4.AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
AOP实现原理
a. aop底层将采用代理机制进行实现。
b. 接口 + 实现类 :spring采用 jdk 的动态代理Proxy。
c. 实现类:spring 采用 cglib字节码增强。
补充(资料来源黑马)
补充(资料来源:六月的余晖博客)
1)Java SE动态代理:
使用动态代理可以为一个或多个接口在运行期动态生成实现对象,生成的对象中实现接口的方法时可以添加增强代码,从而实现AOP。缺点是只能针对接口进行代理,另外由于动态代理是通过反射实现的,有时可能要考虑反射调用的开销。
(2)字节码生成(CGLib 动态代理)
动态字节码生成技术是指在运行时动态生成指定类的一个子类对象,并覆盖其中特定方法,覆盖方法时可以添加增强代码,从而实现AOP。其常用工具是cglib。
(3)定制的类加载器
当需要对类的所有对象都添加增强,动态代理和字节码生成本质上都需要动态构造代理对象,即最终被增强的对象是由AOP框架生成,不是开发者new出来的。解决的办法就是实现自定义的类加载器,在一个类被加载时对其进行增强。JBoss就是采用这种方式实现AOP功能。
(4)代码生成
利用工具在已有代码基础上生成新的代码,其中可以添加任何横切代码来实现AOP。
(5)语言扩展
可以对构造方法和属性的赋值操作进行增强,AspectJ是采用这种方式实现AOP的一个常见Java语言扩展。
个人理解
要增强的类有接口底层就用jdk动态代理,没有接口就用cglib代理(肯定有误,看下面有具体解释)
代码举例:
jdk代理:
写一个增强类()
前后增强实现两个接口(增强那个写那个)
环绕增强类需要实现 org.aopalliance.intercept.MethodInterceptor 接口(相当于同时实现前后增强)
测试:
这里没有用spring管理bean
使用spring
相应类上加上注解 扫描
结果同上
个人理解:
1.getbean(“greetingProxy”)获得的其实也是一个代理 然后强转成我要的类型
2.以上细心的童鞋会发现以上全是对类中某一个方法的增强,如果想对类新增一个方法如何做到.
引入增强
对方法的增强叫做织入 对类的增强叫做引入增强
问题引入 :上面写的类是实现的greeting接口,如果要新增方法的话必须实现接口的方法.这时就需要改类代码了.
而cglib代理的话,不需要实现接口,意思其实是再写一个接口上面写上你的增强方法,再让增强类实现接口,原来的类不用改动只需改配置就可以了(可能存在的误区:cglib也能增强方法)
(纠正:应该是是否启用代理类,启用代理类就是启用cglib,而jdk代理是代理的接口)
代理的是类所以上面用的是impl 要使用新增方法只需强转接口就可以了题外:(资料来源黑马 更详细的介绍)
aop术语
1.target:目标类,需要被代理的类。例如:UserService
2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
3.PointCut 切入点:已经被增强的连接点。例如:addUser()
4.advice 通知/增强,增强代码。例如:after、before
5. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
6.proxy 代理类
7. Aspect(切面): 是切入点pointcut和通知advice的结合
一个线是一个特殊的面。
一个切入点和一个通知,组成成一个特殊的面。
springaop 全自动编程
上面的例子全是半自动的,将代理交给spring来创建
全自动spring配置(看注释理解)
AspectJ是一个基于Java语言的AOP框架
Spring2.0以后新增了对AspectJ切点表达式支持
建议用aspectj
切入点表达式
语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
修饰符,一般省略
public 公共方法
* 任意
返回值,不能省略
void 返回没有值
String 返回值字符串
* 任意
包,[省略]
com.gyf.crm 固定包
com.gyf.crm..service crm包下面子包任意 (例如:com.gyf.crm.staff.service)
com.gyf.crm… crm包下面的所有子包(含自己)
com.gyf.crm..service… crm包下面任意子包,固定目录service,service目录任意包
类,[省略]
UserServiceImpl 指定类
Impl 以Impl结尾
User 以User开头
* 任意
方法名,不能省略
addUser 固定方法
add* 以add开头
*Do 以Do结尾
* 任意
(参数)
() 无参
(int) 一个整型
(int ,int) 两个
(…) 参数任意
throws ,可省略,一般不写。
案例1:
execution(* com.gyf.crm..service….*(…))
案例2:或
<aop:pointcut expression=“execution(* com.gyf.crm.service..(…)) ||
execution(* com.gyf.Do.(…))” id=“myPointCut”/>
within:
匹配包或子包中的方法(了解)
within(com.gyf.aop…*)
this:
匹配实现接口的代理对象中的方法(了解)
this(com.gyf.aop.user.UserDAO)
target:
匹配实现接口的目标对象中的方法(了解)
target(com.gyf.aop.user.UserDAO)
args:
匹配参数格式符合标准的方法(了解)
args(int,int)
bean(id)
对指定的bean所有的方法(了解)
bean(‘userServiceId’)
使用注解配置切面类
///未完待续