AOP是干嘛的
(aspect oriented programming面向切面编程)
简单来说它就是把我们的程序重复代码抽取出来,在需要执行的时候,使用动态代理技术,在不修改源码的基础上,对已有的方法增强
作用:程序运行期间,不修改源码,对已有的方法进行增强
优势:减少重复代码,提高开发效率,维护方便
实现:动态代理技术
案例中的问题(了解)
问题1
用一般的方法控制事务,如果我们每次都执行一条 sql 语句,没有问题,但是如果业务方法一次要执行多条 sql语句,这种方式就无法实现功能了。
解决1----问题2
当我们执行时,由于执行有异常(int i=1/0),转账失败。但是因为我们是每次执行持久层方法都是独立事务,导致无法实现事务控制(不符合事务的一致性)
//业务层实现类的转账方法:
public void transfer(String sourceName, String targetName, Float money) {
//根据名称查询两个账户信息
Account source = accountDao.findByName(sourceName);
Account target = accountDao.findByName(targetName);
//转出账户减钱,转入账户加钱
source.setMoney(source.getMoney()-money);
target.setMoney(target.getMoney()+money);
//更新两个账户
accountDao.update(source);
int i=1/0; //模拟转账异常
accountDao.update(target);
}
解决2----问题3
让业务层来控制事务的提交和回滚。
但是。业务层方法变得臃肿了。并且业务层方法和事务控制方法耦合了。试想一下,如果我们此时提交,回滚,释放资源中任何一个方法名变更,都需要修改业务层的代码,况且这还只是一个业务层实现类,而实际的项目中这种业务层实现类可能有十几个甚至几十个。
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao = new AccountDaoImpl();
public void saveAccount(Account account) {
try {
TransactionManager.beginTransaction();
accountDao.save(account);
TransactionManager.commit();
} catch (Exception e) {
TransactionManager.rollback();
e.printStackTrace();
}finally {
TransactionManager.release();
}
}
public void updateAccount(Account account) {
try {
TransactionManager.beginTransaction();
accountDao.update(account);
TransactionManager.commit();
} catch (Exception e) {
TransactionManager.rollback();
e.printStackTrace();
}finally {
TransactionManager.release();
}
}
public void deleteAccount(Account account) {
******
/*还有很多方法,每个方法都得这么写*/
}
}
使用动态代理技术
特点:字节码随用随创建,随用随加载。
它与静态代理的区别也在于此。因为静态代理是字节码一上来就创建好,并完成加载。装饰者模式就是静态代理的一种体现。
基于接口的动态代理
提供者:JDK 官方的 Proxy 类。
要求:被代理类最少实现一个接口。
基于子类的动态代理
提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。
要求:被代理类不能用 final 修饰的类(最终类)。
JDK 官方的 Proxy 类
以前,演员和剧组都是直接见面联系的。没有中间人环节。而随着时间的推移,产生了一个新兴职业:经纪人(中间人),这个时候剧组再想找演员就需要通过经纪人来找了。下面就用代码演示出来。
/*演员接口*/
public interface IActor {
public void basicAct(float money);
public void dangerAct(float money);
}
/*演员实现*/
public class Actor implements IActor{
public void basicAct(float money){
System.out.println("拿到钱,开始基本的表演:"+money);
}
public void dangerAct(float money){
System.out.println("拿到钱,开始危险的表演:"+money);
}
}
代理实现
public class Client {
public static void main(String[] args) {
//一个剧组找演员:
final Actor actor = new Actor();//直接
/**
* 创建的方式
* Proxy.newProxyInstance(三个参数)
* ClassLoader:和被代理对象使用相同的类加载器。
* Interfaces:和被代理对象具有相同的行为。实现相同的接口。
* InvocationHandler:如何代理。
*/
IActor proxyActor = (IActor) Proxy.newProxyInstance(
actor.getClass().getClassLoader(),
actor.getClass().getInterfaces(),
new InvocationHandler() {
/**
* 执行被代理对象的任何方法,都会经过该方法。此方法有拦截的功能。
* 参数:
* proxy:代理对象的引用。不一定每次都用得到
* method:当前执行的方法对象
* args:执行方法所需的参数
* 返回值:当前执行方法的返回值
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String name = method.getName();
Float money = (Float) args[0];
Object rtValue = null;
if("basicAct".equals(name)){
//基本演出,没有 2000 不演
if(money > 2000){
//看上去剧组是给了 8000,实际到演员手里只有 4000
//这就是我们没有修改原来 basicAct 方法源码,对方法进行了增强
rtValue = method.invoke(actor, money/2);
}
}
if("dangerAct".equals(name)){
//危险演出,没有 5000 不演
if(money > 5000){
rtValue = method.invoke(actor, money/2);
}
}
return rtValue;
}});
//没有经纪公司的时候,直接找演员。
// actor.basicAct(1000f);
// actor.dangerAct(5000f);
//剧组无法直接联系演员,而是由经纪公司找的演员
proxyActor.basicAct(8000f);
proxyActor.dangerAct(50000f);
}
}
第三方的 CGLib (略,和上个差不多)
来源:CSDN
作者:NOOB222
链接:https://blog.csdn.net/qq_41653935/article/details/104157399