概念
面向切面编程。
可以使业务的各个部分相互隔离,耦合度降低,提高程序可重用性,同时提高开发效率
1视频里老师用一个业务来说明,如上图,比如我们做一个登陆功能,用户输入账号密码,表单提交,数据库查询来判断能否登陆。如果我们想在登陆功能基础上加上权限控制,我们先将权限功能做一个模块,然后将这个模块配置到登陆成功后,这就是AOP
底层原理
AOP底层使用的是动态代理,其使用情况分为有接口和没有接口2种情况
有接口,使用jdk的动态代理
没有接口,使用CGLIB的动态代理
2有接口情况如上图,我们做了个接口UserDao,实现类UserDaoImpl,有登陆函数,使用JDK动态代理,创建了接口实现类的代理对象来扩展功能
3没有接口情况如实,比如我们定义了一个类User,想要扩展add方法,可能会使用子类继承,然后添加功能,而CGLIB是创建当前类的子类的代理对象
代码实现动态代理
使用jdk动态代理,有接口情况,我们需要使用jdk的lang包下的Proxy类的静态方法newProxyInstance
4其3个参数,第一个是类加载器,第二个是传递的接口(字节码数组),可以写多个接口,第三个是创建接口InvocationHandler实现类对象,用于写我们代码功能增强的部分
了解后,我们来编写代码
5 6首先创建接口和实现类
7然后就是带main接口的使用类,这里我们定义main方法,使用Proxy的刚才讲过的方法,返回代理实例,这里类加载器使用当前类.class.getClassLoader()获取,然后接口数组使用外部定义,对于InvocationHandler实例参数,由于其是接口,我们需要写实现类,其要复写的方法是invoke方法,默认是返回null的,这里Method是当前执行的方法,args是方法执行的参数,我们可以在前后打印内容,但是我们需要调用实现类对象,所以我们定义属性和有参构造,在main方法里将实现类对象传递进来,
8如上,可以看到功能增加了,这里我们只是了解下如何使用jdk增强功能,实际spring是已经给我们封装好了,到时候我们配置就行。当然如果我们执行的是update方法呢,我们可以通过method对象getName来if判断,根据不同参数来做不同的功能增强
AOP相关术语
Aop有很多术语,我们着重如下4个:连接点,切入点,通知(增强),切面
9连接点:可以被增强的方法,成为连接点
切入点:连接点中被增强的部分
通知:就是增强的代码逻辑,分5种,在前面是前置,后面后置,都有环绕,catch捕获,finally最终执行
切面:把通知应用到切入点的过程
AOP操作准备工作
spring框架中一般基于AspectJ实现AOP操作
AspectJ是独立于Spring的AOP框架
基于AspectJ实现AOP操作有2种方式:xml配置,注解,后者经常使用
导入依赖包
10我们之前的IOC案例,使用的如上的包,已经包含了AOP,这里还需要aspect包
11这个包在spring下面
12还有视频资源的3个aspect依赖包,然后idea设置导入
切入表达式
配置前需要学习切入表达式
作用:知道什么类什么方法被增强
语法结构:execution([权限修饰符如public等][返回类型][类全路径][方法名称](参数列表) )
13例子如上图,我们对指定类,指定方法增强,我们表达式如上,权限修饰符我们可以写public,这里使用*替代,返回类型可以省略,我们的类名写上,然后方法名之间有.连接,参数列表直接使用..,注意*和后面有空格
14然后还有上面2个例子,如上,我们增强只要是所有即可用*替代
使用Aspect注解完成AOP操作
15首先,创建被增强类,我们使用注解创建对象
16虽然是使用注解,但是aop还是需要xml配置,这里就还算是加上组件扫描完成注解,使用context:标签,然后记得使用context名称空间配置修改,同样的配置xmlns:aop和网址,配置后使用aop的自动代理标签
17创建增强代理类,由于要生成对象类需要使用@Component注解完成,同时加上@Aspect,实现将我们之前的配置aop增强识别,我们定义方法before,这里要给其加上@Before注解(注意是使用Aspect包下的),里面value就是我们之前说的切入表达式
18最后编写测试文件,由于使用的是bean.xml配置了注解,还是使用ClassPathXmlApplicationContext,可以看到执行效果,如上
19所以聪明的你也想到了在后面加是使用@After(切入表达式),效果如上
20当然除了这2个注解,我们还有3个注解,@AfterReturning @AfterThrowing @Around,其中,环绕写法是前后增强的,需要使用切入点对象ProceedingJoinPoint类实例,其有proceed()方法,实现控制add此时执行,此方法还要抛出异常。
21执行测试方法,可以看到环绕方法在Before前,after前,但是没有出现异常通知,因为我们没有出现异常
22我们人为制造异常,可以看到运行结果,after被执行了,AfterThrowing也执行,但是没有执行AfterReturning和环绕后,所以@After也叫最终执行
切入点共性提取
我们之前定义了那么多通知来增强功能,实际他们都是对一个切入点进行增强,里面都要写比较长的切入表达式(而且还是一样的),其实这是可以共性抽取的
23我们在代理类里建立一个函数,使用注解@Pointcut就是创建切面,这里我们就把之前的切入点表达式添加进去,然后之前的所有时序的注解value值就可以写成双引号内部函数运行结果,如上。运行效果和之前一样
多增强类增强同一方法设置优先级
24 25我们删掉多余方法只留@Before,复制一份起名UserProxy2,方法执行时设置打印区别
26按默认顺序是先UserProxy再UserProxy2,现在我们想让后者在前怎么办,使用@Order给增强类添加注释,value值越小优先级越高
27 28如上,我们给2设置优先级1,之前的设置2,结果2先运行
AspectJ使用配置文件实现AOP(仅了解)
我们之前使用的是通过注解实现aop,这将是大多数情况(推荐),不过配置文件实现增强也是可以的。
步骤:创建类和增强类,xml创建Bean创建对象,xml配置切入点
29 30首先创建类和增强类如上
31xml文件里还是得有aop名称空间,然后创建2个bean,创建aop配置标签,使用pointcut创建切入点,我们设置id为point,属性expression如上就是切入表达式
32aop配置切入点后,就要配置切面。就是增强函数插入位置,我们idea给出很多提示,相信到这里你已经明白啦
33最后我们设置属性method为函数命名,pointcut-ref为我们的切入点id,运行结果实现before增强
最终完全注解AOP
我们之前使用注解AOP操作,其实还是用了xml文件,如图16,里面使用context标签开启扫描,aop设置自动代理对象创建,
其实是可以只使用注解,一点都不使用aop的
34我们还是文件层级关系,创建配置类,里面@Configuration注解和自动扫描注解
35原始类使用@Component创建实例
36增强类。使用@Aspect创建前面,@Component创建对象@EnableAspectAutoProxy设置自动代理,在这里要给目标类设置true,默认为false
37测试类和结果如上,这里使用的是AnnotationConfig开头的上下文,传入的是配置类的字节码
网友评论