1.什么是AOP, 什么是AspectJ,spring
2. 什么是Spring AOP数据库
3. Spring AOP注解版实现原理编程
4. Spring AOP切面原理解析安全
aop是面向切面编程,相比传统oop,aop可以在方法的前置,中置,后置中插入逻辑代码,对于项目中大量逻辑重复的代码,使用aop能很好的收口逻辑,将逻辑独立于业务代码以外,一处编写,多处使用。ide
AOP是Object Oriented Programming(OOP)的补充.函数
OOP可以很好地解决对象的数据和封装的问题,却不能很好的解决Aspect("方面")分离的问题。下面举例具体说明。oop
好比,咱们有一个Bank(银行)类。Bank有两个方法,save(存钱)和withdraw(取钱)。gradle
类和方法的定义以下:ui
package com.lxl.www.aop; public class Bank { /** * 存钱 */ public Float save(Account account, float money) { // 增长account帐户的钱数,返回帐户里当前的钱数 return null; } /** * 取钱 */ public Float withdraw(Account account, float money) { // 减小account帐户的钱数,返回取出的钱数 return null; } };
这两个方法涉及到用户的帐户资金等重要信息,必需要很是当心,因此编写完上面的商业逻辑以后,项目负责人又提出了新的要求--给Bank类的每一个重要方法加上安全认证特性。spa
因而, 咱们在两个方法上增长安全代码
改后的类和方法以下:
public class Bank { /** * 存钱 */ public Float save(Account account, float money) { // 验证account是否为合法用户 // 增长account帐户的钱数,返回帐户里当前的钱数 return null; } /** * 取钱 */ public Float withdraw(Account account, float money) { // 验证account是否为合法用户 // 减小account帐户的钱数,返回取出的钱数 return null; } };
这两个方法都须要操做数据库,为了保持数据完整性,项目负责人又提出了新的要求--给Bank类的每一个操做数据库的方法加上事务控制。
因而,咱们不得不分别在上面的两个方法中加入安全认证的代码。
类和方法的定义以下:
package com.lxl.www.aop; public class Bank { /** * 存钱 */ public Float save(Account account, float money) { // 验证account是否为合法用户 // begin Transaction // 增长account帐户的钱数,返回帐户里当前的钱数 // end Transaction return null; } /** * 取钱 */ public Float withdraw(Account account, float money) { // 验证account是否为合法用户 // begin Transaction // 减小account帐户的钱数,返回取出的钱数 // end Transaction return null; } };
咱们看到,这些与商业逻辑无关的重复代码遍及在整个程序中。实际的工程项目中涉及到的类和函数,远远不止两个。如何解决这种问题?
AOP就是为了解决这种问题而出现的。在不修改代码的状况下达到加强的效果
对照上图, 来对应每个区域,看看其具体含义
package com.lxl.www.aop.bank; public interface Bank { /** * 存钱 */ Float save(Account account, float money) ; /** * 取钱 */ Float withdraw(Account account, float money); };
package com.lxl.www.aop.bank; import org.springframework.stereotype.Service; /** * 工商银行 * * * DATE 2020/12/6. * * @author lxl. */ @Service public class IcbcBank implements Bank{ @Override public Float save(Account account, float money) {
// 主业务逻辑: 增长account帐户的钱数,返回帐户里当前的钱数 System.out.println(account.getName() + "帐户存入" + money); return null; } @Override public Float withdraw(Account account, float money) {
// 主业务逻辑: 减小account帐户的钱数,返回取出的钱数 System.out.println(account.getName() + "帐户取出" + money); return null; } }
package com.lxl.www.aop.bank; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.DeclareParents; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * 切面 */ @Aspect // 标记这是一个切面 @Order @Component // 将其放到ioc容器管理 public class BankLogAspect { /** * 引入 * * 这段话能够理解为, 为com.lxl.www.aop.bank.IcbcBank 引入了一个接口 EnhanceFunctionOfBank, * 同时, 引入了默认的实现类 IcbcEnhanceFunctionOfBank */ @DeclareParents(value = "com.lxl.www.aop.bank.IcbcBank", // 引入的目标类. 也就是须要引入动态实现的类 defaultImpl = IcbcEnhanceFunctionOfBank.class) // 引入的接口的默认实现 public static EnhanceFunctionOfBank enhanceFunctionOfBank; // 引入的接口 /** * 定义一个切点 */ @Pointcut("execution(* com.lxl.www.aop.bank.IcbcBank.*(..))") public void pointCut() {} /** * 定义一个前置通知 * @param joinPoint */ @Before(value = "pointCut()") public void beforeAdvice(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("执行目标方法"+methodName+"的前置通知"); } /** * 定义了一个后置通知 */ @After(value = "pointCut()") public void afterAdvice(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("执行目标方法"+methodName+"的后置通知"); } /** * 定义了一个返回通知 */ @AfterReturning(value = "pointCut()", returning = "result") public void returningAdvice(JoinPoint joinPoint, Object result) { String methodName = joinPoint.getSignature().getName(); System.out.println("执行目标方法"+methodName+"的返回通知"); } /** * 定义了一个异常通知 */ @AfterThrowing(value = "pointCut()") public void throwingAdvice(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("执行目标方法"+methodName+"的异常通知"); } }
那么这里的目标对象是谁呢? 就是咱们的IcbcBank类. 这里须要注意的是引入: 引入的概念是将一个接口动态的让另外一个类实现了. 这样实现了接口的类, 就能够动态的拥有接口实现类的功能.
package com.lxl.www.aop.bank; /** * 加强的功能 */ public interface EnhanceFunctionOfBank { void Financialanagement(Account account); }
package com.lxl.www.aop.bank; import org.springframework.stereotype.Service; /** * Description */ @Service public class IcbcEnhanceFunctionOfBank implements EnhanceFunctionOfBank { /** * 理财功能 * @param account */ @Override public void Financialanagement(Account account) { System.out.println(account.getName() +"的帐户 增长 理财功能"); } }
这个功能咱们能够经过引入,动态增长到IcbcBank类中, 本来IcbcBank只有存钱和取钱的功能. 这样, 就能够增长理财功能了. 这就是引入.
package com.lxl.www.aop.bank; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configurable // 使用注解的方式引入AOP @EnableAspectJAutoProxy @ComponentScan("com.lxl.www.aop.bank") public class BankMainConfig { }
使用aop,须要引入AOP, 这里使用的注解的方式引入的.
package com.lxl.www.aop.bank; import com.lxl.www.aop.Calculate; import com.lxl.www.aop.MainConfig; import com.lxl.www.aop.ProgramCalculate; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class BankMainClass { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BankMainConfig.class); Account account = new Account("张三"); Bank bank = (Bank) ctx.getBean("icbcBank"); bank.save(account, 100); System.out.println(); EnhanceFunctionOfBank enhanceFunctionOfBank = (EnhanceFunctionOfBank) ctx.getBean("icbcBank"); enhanceFunctionOfBank.Financialanagement(account); } }
如上, 运行结果:
最后咱们还须要引入到指定的项目中
以上就是对整个AOP的理解. 接下来, 分析AOP的源码.
详见第二篇文章
as