传统的登录原理:
如上图所示这是一个基本的登录原理图,但是如果我们想要在这个登录之上添加一些新的功能,比如权限校验
那么我们能想到的就有两种方法:
①:通过对源代码的修改实现
②:不通过修改源代码方式添加新的功能 (AOP)
什么是AOP的技术?
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程
AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构
AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范
通过预编译方式或者运行期动态代理实现程序功能的统一维护的一种技术
AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍
生范型
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可
重用性,同时提高了开发的效率
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(事务管理、安全检查、缓存)
为什么要学习AOP,可以在不修改源代码的前提下,对程序进行增强!!
运行期间,不修改源代码的情况下对已有的方法进行增强
优势:
JDK的动态代理技术
1、为接口创建代理类的字节码文件
2、使用ClassLoader将字节码文件加载到JVM
3、创建代理类实例对象,执行对象的目标方法
cglib代理技术
为类生成代理对象,被代理类有没
Joinpoint(连接点) 类里面有哪些方法可以增强这些方法称为连接点
Pointcut(切入点) – 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
Advice(通知/增强)-- 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Aspect(切面)-- 是 切入点+通知 的结合,以后咱们自己来编写和配置的
增强:是对业务功能的扩充
AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,AspectJ实际上是对AOP编程思想的一个实践.
创建被增强的类:
public class Demo { //要增强,成为---->连接点---->切入点 public void login(){ //int a=10/0; System.out.println("登录。。。"); } }
将目标类配置到Spring中:
<bean id="demo" class="com.qcby.Demo"/>
定义切面类
package com.notice; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component @Aspect //表明我们是通知 public class Power { //前置通知的方法 public void authentication(){ System.out.println("登录前---权限验证。。。"); } }
在spring.xml中配置文件中定义切面类:
<bean id="power" class="com.notice.Power"/>
在spring.xml中配置切面:
<aop:config> <!--aspect:前置通知,在登录前执行--> <aop:aspect ref="power"> <!--前置通知:--> <!--method:登录前执行的方法,权限验证的方法--> <!--pointcut:切入点,之后最终要执行的方法--> <!--前置通知:--> <aop:before method="authentication" pointcut="execution(public void com.qcby.Demo.login())"/> </aop:aspect> </aop:config>
测试:
public class DemoTest { @Test public void demo1(){ ApplicationContext ac = new ClassPathXmlApplicationContext("Spring.xml"); Demo demo = (Demo) ac.getBean("demo"); demo.login(); } }
也可以在spring.xml中加入其他通知方式:
<aop:config> <!--aspect:前置通知,在登录前执行--> <aop:aspect ref="power"> <!--前置通知:--> <!--method:登录前执行的方法,权限验证的方法--> <!--pointcut:切入点,之后最终要执行的方法--> <!--前置通知:--> <aop:before method="authentication" pointcut="execution(public void com.qcby.Demo.login())"/> <!--后置通知:当方法执行不成功的时候方法不执行--> <aop:after-returning method="authenticationEnd" pointcut="execution(public void com.qcby.Demo.login())"/> <!--当切入点(登录方法)发生异常的时候执行,没有异常则不执行:--> <aop:after-throwing method="findThrowError" pointcut="execution(public void com.qcby.Demo.login())"/> <!--最终通知:无论切入点的方法执行成功与否,最终都执行的通知(增强)--> <aop:after method="finallyMethod" pointcut="execution(public void com.qcby.Demo.login())"/> <!--环绕通知:在切面前后执行方法--> <aop:around method="round" pointcut="execution(public void com.qcby.Demo.login())"/> </aop:aspect> </aop:config>
@Before – 前置通知
@AfterReturing – 后置通知
@Around – 环绕通知(目标对象方法默认不执行的,需要手动执行)
@After – 最终通知
@AfterThrowing – 异常抛出通知
package com.notice; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component @Aspect //表明我们是通知 public class Power { //增强的方法:权限验证 //@Before(value="execution(public void com.qcby.Demo.login())") //@AfterReturning(value="execution(public void com.qcby.Demo.login())") //前置通知 @Before(value="execution(public void com.qcby.Demo.login())") public void authentication(){ System.out.println("登录前---权限验证。。。"); } //后置通知 @AfterReturning(value="execution(public void com.qcby.Demo.login())") public void authenticationEnd(){ System.out.println("登录后---权限验证。。。"); } //发生异常时通知 @AfterThrowing(value="execution(public void com.qcby.Demo.login())") public void findThrowError(){ System.out.println("登录发现异常了"); } //最终通知 @After(value="execution(public void com.qcby.Demo.login())") public void finallyMethod(){ System.out.println("最终都执行的通知"); } //环绕通知 @Around(value="execution(public void com.qcby.Demo.login())") public void round(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("在登录之前进行了权限验证"); //之间执行登录的方法 proceedingJoinPoint.proceed(); System.out.println("在登录之后进行了权限验证"); } }