AOP的理论学习
1 动态代理
实现方式:jdk动态代理,使用jdk中的Proxy、Method、InvocationHanderl创建代理对象。jdk动态代理要求目标类必须是实现接口
cglib动态代理:第三方的工具库,创建代理对象,原理是继承。通过继承目标类、创建子类。子类就是代理对象。要求目标类不能是final的,方法也不能是final的。
2 动态代理的作用:
- 在目标类源码不改变的情况下,增加功能。
- 减少代码的重复
- 专注业务逻辑代码
- 解耦合,让你的业务功能和日志,事物非业务功能分离
3 Aop:面向切面编程,基于动态代理的,可以使用jdk,cglib两种代理方式
Aop就是动态代理的规范化,把动态代理的实现步骤,方式都定义好,让开发人用一种统一的方式,使用动态代理。
4 怎么理解面向切面编程
- 需要在分析项目功能时,找出切面
- 合理的安排切面执行时间(在目标方法前,还是目标方法后)
- 合理的安排切面执行的位置,在哪个类,哪个方法增加增强功能
术语:
- Aspect:切面,表示增强的功能,就是一堆代码,完成某一个功能。非业务功能,常见的切面功能有日志,事务,统计信息,参数检查,权限验证
- JoinPoint:连接点,连接业务方法和切面的位置,就某个类中的业务方法
- Poincut:切入点,指多个连接点方法的集合。多个方法
- 目标对象:给哪个类的方法增加功能,这个类就是目标对象
- Advice:通知,通知表示切面执行功能的时间
AOP的实现:
AOP是一个规范,是动态代理的一个规范化,一个标准
aop的技术实现框架:
1 Spring:Spring在内部实现了aop规范,能做aop的工作。Spring主要在事务处理使用aop。在项目开发很少用Spring的aop实现。因为Spring的aop比较笨重。
2 aspectJ:一个开源专门做aop的框架。Spring框架中集成了aspectJ框架,通过Spring就能使用aspectJ的功能。
aspectJ框架实现aop有两种方式:
- 使用xml的配置文件:配置全局事物
- 使用注解,我们在项目中要做aop功能,一般使用注解,aspectJ有5个注解。
aspectJ的使用
切面的执行时间,这个执行时间在规范中叫做Advice(通知,增强)
在aspectJ框架中使用注解表示的。也可以使用xml配置文件中的标签。
- @Aspect :是aspectJ框架中的注解。作用:表示当前类是切面类。切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码。位置:在类定义的上面。
- @Before :前置通知注解。属性:value,是切面点表达式,表示切面的功能执行的位置。位置:在方法的上面。特点:1 在目标方法之前执行。 2 不会改变目标方法的执行结果。3 不会影响目标方法的执行。
- @AfterReturning
- @Around
- @AfterThrowing
- @After
表示切面执行的位置,使用的是切入点表达式
com.service.impl
com.bjpowrnode.service.impl
cn.crm.bjpowernode.service
execution(* *..service.*.*(..))
AOP的代码实现
实现步骤:
使用aspectj实现aop的基本步骤: 1.新建maven项目 2.加入依赖 1)spring依赖 2)aspectj依赖 3)junit单元测试 3.创建目标类:接口和他的实现类。 要做的是给类中的方法增加功能 4.创建切面类:普通类 1)在类的上面加入 @Aspect 2)在类中定义方法, 方法就是切面要执行的功能代码 在方法的上面加入aspectj中的通知注解,例如@Before 有需要指定切入点表达式execution() 5.创建spring的配置文件:声明对象,把对象交给容器统一管理 声明对象你可以使用注解或者xml配置文件<bean> 1)声明目标对象 2)声明切面类对象 3)声明aspectj框架中的自动代理生成器标签。 自动代理生成器:用来完成代理对象的自动创建功能的。 6.创建测试类,从spring容器中获取目标对象(实际就是代理对象)。 通过代理执行方法,实现aop的功能增强。
@Pointcut
@Pointcut(value = "execution(void *..do*(..))")
public void myCut(){
}
@Before
@Before(value = "myCut()")
public void myBefore(){
System.out.println("2=====前置通知, 切面功能:在目标方法之前输出执行时间:"+ new Date());
}
@AfterReturning
@AfterReturning(value = "myCut()",returning = "res")
public void myAfterRetuning(Object res){
System.out.println("后置通知, 切面功能:事务");
System.out.println(res);
}
@Around
@Around(value = "myCut()")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("2=====前置通知, 切面功能:在目标方法之前输出执行时间:"+ new Date());
Object proceed = pjp.proceed();
System.out.println("后置通知, 切面功能:事务");
return proceed;
}
Test: 得到的impl是动态代理类对象
@Test
public void test01(){
ApplicationContext ac =
new ClassPathXmlApplicationContext("applicationContext.xml");
SomeService impl =(SomeService) ac.getBean("someServiceImpl");
System.out.println(impl.getClass().getName());
impl.doSome("肖路遥",25);
}