一、AOP思想及相关术语
1、AOP(Aspect Orient Programing)---面向切面编程
(1) 其底层实现就是动态代理
AOP是动态代理技术的一种规范化,让实现灵活的动态代理用一种统一的方式实现,避免矛盾
(2)切面(Aspect)
给目标类增加的功能,就是切面,如给原程序添加的日志和事务功能就是切面
(3) 切面特点:一般都是非业务功能,可独立使用
2、AOP的作用(动态代理的作用)
(1)在不改变原来业务代码的基础上,额外增加业务功能
(2)减少代码的重复
(3)专注业务逻辑代码
(4)解耦合,让业务功能和日志、事务等非业务功能分离
3、常见几种编程思想
OOP:面向对象编程
以对象为基础来构建类,并表示类的属性,类之间关系
首先分析功能,功能中用到那些对象,以对象构建类,类中有那些属性,类与类之间是什么关系,继承 实现等
OIP:面向接口编程
解耦合
AOP:面向切面编程的理解
(1)需要在分析项目功能时,找出切面,即哪些功能是非业务的,可独立使用的附加功能
(2)合理安排切面的执行时间,在目标方法前还是后
(3)合理的安全切面执行的位置,在哪个类,哪个方法增加功能
以切面为核心,分析出切面,合理安排切面的执行时间和位置
4、AOP术语:
(1)Aspect:切面,表示增强的功能,即一堆代码完成某个功能(非业务功能)
常用切面:日志,事务,统计信息,参数检查,权限验证
(2)JoinPoint:连接点,连接业务方法和切面的位置,即某个类中要增强的业务方法,
如 someService接口实现类中的doSome和doOther方法
(3)Pointcut:切入点,指多个连接点的集合, 多个方法都要增强这个功能(切入点表达式)
(4)目标对象:给哪个类的方法增加功能,这个类就是目标对象
(5)Advice:通知,表示切面功能执行的时间,即执行顺序,在目标方法的哪里执行
5、切面三要素
(1)切面:切面的功能代码,切面是具体干什么的(aspect 切面一般封装在util包下)
(2)切入点:切面的执行位置,哪些方法需要增强(Pointcut 切入点)
(3)通知:切面的执行时间,在方法前执行还是方法后执行(Advice 通知)
二、动态代理
1、动态代理可以是jdk和cglib两种方式
AOP将动态代理的实现步骤、方式都定义好了,让开发人员用一种统一的方式实现动态代理
2、jdk动态代理----实现接口
(1)功能类---实现接口InvocationHandler
(2)类中invoke方法-----写功能代码
(3)proxy类---用来创建代理对象
代码详见动态代理部分:待补充
3、cglib动态代理---继承
(1)使用FastClass机制为代理类和被代理类各生成一个类
生成的这个类会为各自代理类或被代理类的方法生成一个index
(2)方法的index被作为参数直接定位到要调用的方法
(3)第三方工具库实现代理对象的创建,要求目标类可继承
具体见:详述 动态代理---JDK动态代理和cglib动态代理_@snow'的博客-CSDN博客_cglib动态代理和jdk代理
三、aspectj框架实现
1、aspectj框架介绍
一个开源的 专门做AOP的框架(来自eclipse)
spring框架中集成了aspectJ框架,通过spring就能使用aspectJ功能
2、 aspectJ框架实现AOP的两种方式
<1>使用xml配置文件:主要用于配置全局事务
<2>使用注解:项目中实现AOP功能一般使用注解
3、aspectJ的五个注解---切面的执行时间----Advice 通知(增强)
(1) @Before 前置通知
- 方法之前执行;
- 没有返回值
(2)@AfterReturing 后置通知
- 原方法之后执行;
- 要传参数,有返回值
(3) @Around 环绕通知
- 可前可后,主要依据实现部分增强方法相对于被增强方法的位置
- 必须有返回值,一般用于事务的处理
(4)@AfterThrowing 异常通知
- 方法没有返回值
- 方法可以没有参数,如果有就是JoinPoint
- 调用的方法有异常,该通知注解的方法才会执行,并抛出信息,没有异常时不执行
(5)@After 最终通知
- 总会执行的,功能同异常中的finally
- 即使有异常也会执行
4、切面的执行位置----切入点表达式:
(1)一般形式
@before(value="execution(访问权限 方法返回值 方法声明(参数) 异常类型)")
其中访问权限和异常类型可省略 , 必有的是方法返回值和方法名及对应参数
(2)表达式中的通配符:
(3)例子
5、实现步骤
(1)在Maven工程xml文件 pom.xml中加入依赖
- spring依赖
- aspectj依赖
- Junit单元测试依赖
(2)创建目标类
一般为service接口及其实现类
(3)创建切面类 --- java普通类,用来实现增加的功能
<1>在类上加@Aspect
<2>在类中定义方法实现功能
指定切面执行时间---在方法上加aspectj的通知注解,@before @after
指定切面执行位置---切入点表达式 execution()
(4)创建spring的配置文件 声明对象-----把对象交给容器统一管理(xml或注解方式)
<1>声明目标对象
<2>声明切面对象
<3>声明aspectj框架中的 自动代理生成器 用来完成代理对象的自动创建功能
(5)测试中通过动态代理对象调用原方法,代理对象实际调用增强后的方法,完成功能添加实现
6、代码实现
- 目标类
//目标类接口
public interface SomeService{
pubblic void doSome(String name,Integer age);
}
//接口类实现类
public class SomeServiceImpl inplements SomeService{
pubblic void doSome(String name,Integer age){
System,.out.println("这是目标方法");
}
}
- 切面类
@Aspect
public class MyAspect{
@Before(value=
"execution(public void com.sqf.service.SomeServiceImpl.doSome(String,Integer))")
public void myBefore(){
//切面要执行的代码
System.out.println("前置通知:在目标方法之前输出执行时间:"+new Date());
}
}
- spring配置文件中声明目标对象、切面对象和自动代理生成器
<bean id="someService" class="com.sqf.service.SomeServiceImpl">
<bean id="myAspect" class="com.sqf.service.myAspect">
<aop:aspectj-autoproxy>
[注]两种代理的使用情况:
一般目标类是一个接口实现类(SomeServiceImpl )-------默认使用jdk动态代理
若目标类非接口实现类,是普通类(Student)--------默认使用cglib动态代理
若是接口实现类想要强制使用cglib-----<aop:aspectj-autoproxy proxy-target-class=true>
- 测试:通过容器获取代理对象
String config="applicationContext.xml";//spring配置文件名
Application ctx=ClassPathXmlApplicationContext("config");//创建容器对象
SomeService proxy=(SomeService)ctx.getBean("someService");//通过容器获取目标对象的代理对象
proxy.doSome('zs'.20);//代理对象执行的方方,实际是增强了功能----先输出时间,再输出"这是目标方法"
这是动态代理规范化的实现方法,一般动态代理实现详见动态代理----待补充