21.05.10
什么是AOP
AOP(Aspect-Oriented Programming,面向切面编程)是对传统传统 OOP(Object-Oriented Programming,面向对象编程)的补充,属于一种横向扩展。其将与核心业务无关的代码,如日志记录、性能监控、事务处理等从业务逻辑代码中抽离出来,进行横向排列,从而实现低耦合,提高开发效率。
怎样理解面向切面编程
使用aop的目的:是个已经存在的一些类和方法,增加额外的功能,前提是不改变原来类的代码
1)需要在分析项目功能时,找出切面
2)合理的安排切面的执行时间(在目标方法前,还是目标方法后)
3)合理的安放切面执行的位置,在哪个类,哪个方法增加增强功能
术语
1)Aspect:切面,表示增强的功能,就是一堆代码,完成某个一个功能。给业务功能,常见的切面功能有日志,事务,统计信息,参数检查,权限验证
2)JoinPoint:连接点,连接业务方法和切面的位置,就某类中的业务方法
3)Pointcut:切入点,指多个连接点方法的集合。多个方法
4)目标对象:给哪个类增加功能,哪个就是目标对象
5)Advice:通知,通知表示切面功能执行的时间
一个切面的三个关键的要素
1)切面的功能代码,切面干什么
2)切面的执行位置,使用Pointcut表示切面执行的位置
3)切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后
aop的实现
aop是一个规范,是动态的一个规范化,一个标准
sop的技术实现框架:
1.spring:spring在内部实现了aop规范,能做aop的工作
spring主要在事务处理时使用aop
我们项目开发中很少使用spring的aop实现(笨重)
2.aspectJ:一个开源的专门做aop的框架,spring框架中集成了aspectJ框架,通过spring就能使用aspectj的功能。
aspectj框架事项aop的两种方式:
1)使用xml的配置文件:配置全局事务
2)使用注解,我们在项目中要做aop功能,一般都是用注解,aspectj有5个注解
@Before @AfterReturning @Around @AfterThrowing @After
AsjpectJ的切入点给表达式
使用aspectj实现aop的基本步骤:
1.新建maven项目
2.加入依赖
1)spring依赖
2)aspectj依赖
3)junit单元测试
3.创建目标类:接口和他的实现类。要做的是给类中的方法增加功能
4.创建切面类:普通类
1)在类的上面加入@Aspect
2)在类中定义方法,方法就是切面要执行的功能代码
5.创建spring的配置文件:声明对象,把对象交给容器统一管理
声明对象可以使用注解或者xml配置文件 < bean >
1)声明目标对象
2)声明切面类对象
3)声明aspectj框架中的自动代理生成器标签
自动代理生成器:用来完成代理对象的自动创建功能的
6.创建测试类,从spring容器中获取目标对象(实际就是代理对象)
通过代理执行方法,实现aop的功能增强
<!--aspectj依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.1</version>
</dependency>
@Aspect
aspect框架中的注解
作用:表示当前类是切面类
切面类:是用来个业务方法增加功能的类,在这个类中有切面的功能代码
位置:在类定义的上面
/*
* 定义方法,方法是事项切面功能的。
* 方法定义要求:
* 1.公共方法public
* 2.方法没有返回值
* 3.方法名称自定义
* 4.方法可以有参数,也可以没有参数
* 如果有参数,参数不是自定义的,有几个参数类型可以使用
*/
SomeService.java
package com.node.ba01;
public interface SomeService {
void doSome(String name,Integer age);
}
SomeServiceImpl.java
package com.node.ba01;
public class SomeServiceImpl implements SomeService {
@Override
public void doSome(String name,Integer age) {
//给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
System.out.println("===目标方法doSome===");
}
}
MyAspect.java
package com.node.ba01;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import java.util.Date;
@Aspect
public class MyAspect {
@Before(value="execution(public void com.node.ba01.SomeServiceImpl.doSome(String,Integer))")
public void myBefore(){
//就是你切面要执行的功能代码
System.out.println("切面功能:在目标方法之前输出执行时间:"+ new Date());
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--把对象交给spring容器,由spring容器统一创建,管理对象-->
<!--声明目标对象-->
<bean id="someService" class="com.node.ba01.SomeServiceImpl"/>
<!--声明切面类对象-->
<bean id="myAspect" class="com.node.ba01.MyAspect" />
<!--声明自动代理生成器-->
<!--使用aspectj框架内部的功能,创建目标对象的代理对象
创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象,
所以目标对象就是被修改后的代理对象
aspectj-autoproxy:会把spring容器中的所有目标对象,一次性都生成代理对象
-->
<aop:aspectj-autoproxy />
</beans>
测试代码
package com.node;
import com.node.ba01.SomeService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest01 {
@Test
public void test01(){
String config="applicationContext.xml";
ApplicationContext ac=new ClassPathXmlApplicationContext(config);
//从容器中获取目标对象
SomeService proxy= (SomeService) ac.getBean("someService");
//通过代理的对象执行方法,事项目标方法执行时,增强了功能
proxy.doSome("lisi",20);
//com.sun.proxy.$Proxy6:jdk动态代理
System.out.println(proxy.getClass().getName());
}
}