1.什么是AOP, 什么是AspectJ,
2. 什么是Spring AOP
3. Spring AOP注解版实现原理
4. Spring AOP切面原理解析
aop是面向切面编程,相比传统oop,aop能够在方法的前置,中置,后置中插入逻辑代码,对于项目中大量逻辑重复的代码,使用aop能很好的收口逻辑,将逻辑独立于业务代码之外,一处编写,多处使用。
AOP是Object Oriented Programming(OOP)的补充.
OOP能够很好地解决对象的数据和封装的问题,却不能很好的解决Aspect("方面")分离的问题。下面举例具体说明。
比如,我们有一个Bank(银行)类。Bank有两个方法,save(存钱)和withdraw(取钱)。
类和方法的定义如下:
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类的每个重要方法加上安全认证特性。
于是, 我们在两个方法上增加安全代码
改后的类和方法如下:
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就是为了解决这种问题而出现的。在不修改代码的情况下达到增强的效果
对照上图, 来对应每一个区域,看看其具体含义
那么在Spring中使用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+"的异常通知");
}
}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() +"的账户 增加 理财功能");
}
}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 {
}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