学习spring(4)AOP使用场景

99封情书 提交于 2020-02-04 01:41:12

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 (略,和上个差不多)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!