一、Spring中AOP(Aspect Oriented Programming)的实现
Spring实现AOP两种方式:
- 目标类实现了接口,采用JDK的动态代理实现AOP功能
- 目标类没有实现任何接口,采用CGLIB的类库实现AOP功能
- Spring会自动在这两种方式进行选择
- 使用Spring创建代理类对象的Bean标签的Property属性名要和对应setProperty方法保持一致
- Spring动态代理会对目标类对象和代理类对象,代理的Object父类的HashCode和equals方法进行特殊处理
AOP面向切面编程的概念:
- AOP:面向切面编程的思想。是一种对开发技术的补充,允许开发人员在不改变原来模型的基础上动态的修改模型以满足新的需求
- aspect:切面/切面类。实现新增功能的类
- wave:将新增功能的添加到目标类对象的方法中的过程(即实现代理类对象代理目标类对象的方法的过程)
- joinPoint:连接点。在Spring中指代目标类中需要代理的方法。在AOP思想中,连接点可以是一个类,也可以是一个属性等等
- pointCut:切入点。连接点的集合,目标类中需要新增该功能的一组方法的集合
- advice:通知/拦截器。设置实现新增功能的方法在目标类对象的镜像方法执行的位置
- 前置通知(Before advice):
在某些连接点(join point)之前执行的通知 - 返回后通知(After returning advice):
在某些连接点(join point)正常完成后执行的通知(方法正常结束,没有异常) - 抛出异常后通知(After throwing advice):
在某些连接点(join point)抛出异常退出时执行的通知 - 后通知(After (finally) advice):
当某些连接点(join point)退出的时候执行的通知 - 环绕通知(Around Advice):
包围一个连接点(join point)的通知,例如事务的处理,就需要这样的通知,因为事务需要在方法前开启,在方法后提交,以及方法抛出异常时候回滚
- 前置通知(Before advice):
- advisor:增强器。筛选哪些方法是我们的连接点
Bean类
//银行账户
public class Account {
private int id;
private String name;
//余额
private double balance;
get/set...
}
//dao层接口
public interface AccountDao {
//取款 账号减去多少钱
void withdraw(Account acc,double amt);
//存款 账号加上多少钱
void deposit(Account acc,double amt);
}
//dao实现类
public class AccountDaoImpl implements AccountDao{
//取款
@Override
public void withdraw(Account acc, double amt) {
System.out.println("账号成功取款"+amt);
}
//存款
@Override
public void deposit(Account acc, double amt) {
System.out.println("账号成功存款"+amt);
}
}
//service层
public interface IAccountService {
//转账
void bankAction();
}
//service实现类
//目标对象(target)
public class AccountServiceImpl implements IAccountService{
private AccountDao accountDao;
private Account account;
//转账
public void bankAction(){
accountDao.withdraw(account, 100);
accountDao.deposit(account, 100);
//throw new RuntimeException("我的异常测试");
}
get/set方法...
}
通知/拦截器
-
advice:所有的拦截器都间接实现了Advice接口,该接口没有任何方法(类似于Serializable,Cloneable接口),只是实现规范告诉实现该接口的实现类为拦截器(属于第三方jar包org.aopalliance)
-
前置通过/拦截器
//MethodBeforeAdvice继承了BeforeAdvice接口,BeforeAdvice继承了Advice接口 public class BeforeAdvice implements MethodBeforeAdvice { private MyLogger logger; public MyLogger getLogger() { return logger; } public void setLogger(MyLogger logger) { this.logger = logger; } // 表示在被代理的目标执行之前,回调该方法 // 1.执行目标类的方法的镜像方法 // 2.镜像方法的参数 // 3.目标类对象 // Object有可能为null,因为有可能静态方法,代理类的静态方法无关对象,所以有可能为null @Override public void before(Method method, Object[] args, Object target) throws Throwable { //在执行目标类的镜像方法之前执行 logger.log(target.getClass().getSimpleName()+"的"+method.getName() + "方法执行!"); //Spring会自动执行镜像方法 //arg0.invoke(arg2, arg1); } } Spring配置文件 <!-- Spring管理所有类的对象,注入到bean容器 --> <!-- MyLogger实现日志功能的类 --> <bean id="logger" class="com.briup.aop.aspect.MyLogger"></bean> <!-- AccountDaoImpl.java --> <bean id="dao" class="com.briup.aop.dao.AccountDaoImpl"></bean> <!-- Account.java --> <bean id="account" class="com.briup.aop.pojo.Account"> <property name="id" value="1"/> <property name="name" value="zs"/> <property name="balance" value="10000"/> </bean> <!-- 将目标类对象注入到bean容器中 --> <bean id="target" class="com.briup.aop.service.AccountServiceImpl"> <property name="accountDao" ref="dao"/> <property name="account" ref="account"/> </bean> <!-- 配置拦截器beforeAdvice --> <bean id="beforeAdvice" class="com.briup.aop.before.BeforeAdvice"> <property name="logger" ref="logger"/> </bean> <!-- 配置代理类:采用JDK实现接口的方式生成代理对象 --&
-