spring系列(三):切面编程(aop)1

一  简介

     面向切面编程(Aspect Oriented Programming,AOP)是软件编程思想发展到一定阶段的产物,是对面向对象编程(Object Oriented Programm ing,OOP)的有益补充。AOP -般适用于具有横切逻辑的场合,如访问控制、事务管理、性能监测等。

什么是横切逻辑呢?我们先来看下面的程序代码。

/**
 * 学生业务类,实现对Student功能的业务管理
 */
public class StudentBiz implements IStudentBiz {
	private static final Logger log = Logger.getLogger(StudentBiz.class);
	// 声明接口类型的引用和具体实现类解耦合
	private IDao dao;
	// dao属性的setter访问器,会被Spring调用,实现设值注入
	public void setDao(IDao dao) {
		this.dao = dao;
	}
	public void addNewStudent(Student student) {
		log.info("添加学生" + student.getName());
		Transaction tx = null;
		try {
			tx = HibernateSessionFactory.getSession().beginTransaction();
			// 调用学生Dao的方法,保存学生信息
			dao.save(Studnet);
			tx.commit();
		} catch (Exception e) {
			log.error("添加学生" + student.getName() + "失败", e);
			if (tx != null) {
				tx.rollback();
			}
		}
	}
}

这是一个再“典型”不过的业务处理方法。日志、异常处理、事务控制等,都是一个健壮的业务系统所必需的。但是为了保证系统健壮可用,就要在众多的业务方法中反复编写类似的代码,使得原本就很复杂的业务处理代码变得更加复杂。业务功能的开发者还要考虑这些“额外”的代码是否处理正确、是否有遗漏的地方。如果需要修改日志信息的格式或者安全验证的规则,或者再增加新的辅助功能,都会导致业务代码频繁而大量的修改。

在业务系统中,总有一些散落、渗透到系统各处且不得不处理的事情,这些穿插在既定业务中的操作就是所谓的“横切逻辑”,也称为“切面”。我们怎样才能不受这些附加要求的干扰,专心于真正的业务逻辑上呢?我们很容易想到可以将这些重复性的代码抽取出来,放在专门的类和方法中,这样就便于管理和维护了。但即便如此,依然无法实现既定业务和横切逻辑的彻底解耦合,因为业务代码中还要保留这些方法的调用代码,当需要增加或减少横切逻辑的时候,还是要修改业务方法中的调用代码才能实现。我们希望无须编写显式的调用,在需要的时候,系统能够“自动”调用所需的功能,这正是AOP要解决的主要问题。

面向切面编程,简单地说就是在不改变原程序的基础上为代码段增加新的功能,对代码段进行增强处理。它的设计思想来源于代理设计模式,下面以图示的方式进行简单的说明。通常情况下调用对象的方法如图所示。


在代理模式中可以为该对象设置一个代理对象,代理对象为fun()提供一个代理方法,当通过代理对象的fun()方法调用原对象的fun()方法时,就可以在代理方法中添加新的功能,也就是所谓的增强处理,增强的功能既可以插到原对象的fun()方法前面,也可以插到后面,如图所示。


在这种模式下,给编程人员的感觉是在原有代码乃至原业务流程都不修改的情况下,直接在业务流程中切入新代码,增加新功能,这就是所谓的面向切面编程。对面向切面编程有了感性认识以后,还需要了解它的以下一些基本概念。

Ø  增强处理(Advice)类型:在上图中,在原对象的fun()方法之前插入的增强处理为前置增强,该方法正常执行完以后插入的增强处理为后置增强,此外还有环绕增强、异常抛出增强、最终增强等类型。

Ø  切人点(Pointcut):可以插入增强处理的方法,图1.8中原对象的fun()方法就是一个切入点。

Advice直译为“通知”,但这种叫法并不确切,在此处翻译成“增强处理”更便于大家理解。


二  具体案例

2.1  前置增强处理

1.  建立工程,导入相关jar包


建立spring核心配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	                    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	                    http://www.springframework.org/schema/aop
	                    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
	
	<bean id="userDao" class="com.obtk.dao.UserDaoImpl"></bean>
	<!--要素1   增强处理的代码 -->
	<bean id="beforAdvise" class="com.obtk.advise.BeforAdvise"></bean>
	<aop:config>
	    <!--要素2   切入点 -->
		<aop:pointcut  id="mycut"
          expression="execution(public int com.obtk.dao.UserDaoImpl.saveUser(com.obtk.entitys.UserEntity))"/>
	    <!--要素3   织入 -->
	    <aop:advisor advice-ref="beforAdvise" pointcut-ref="mycut"/>
	    
	</aop:config>
</beans>
=================UserDaoImpl.java===========================

package com.obtk.dao;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;

import com.obtk.entitys.UserEntity;
import com.obtk.utils.MybatisUtil;

public class UserDaoImpl implements IUserDao{
	
	public int saveUser(UserEntity theUser) {
		System.out.println("方法执行前....");
		int result=0;
		SqlSession session=null;
		try {
			//4.得到session
			session=MybatisUtil.getSession();
			//5.执行语句
			result=session.insert("user.saveOne", theUser);
			session.commit();
			//添加完成可以取出启动增长的主键
			System.out.println("添加成功!");
		} catch (Exception e) {
			session.rollback();
			e.printStackTrace();
		}finally{
			MybatisUtil.closeSession();
		}
		return result;
	}
	
}
mybatis相关配置在这里省略,请参考我的mybatis相关博文。

增强处理代码:

============BeforAdvise.java================

package com.obtk.advise;

import java.lang.reflect.Method;
import java.util.Arrays;

import org.springframework.aop.MethodBeforeAdvice;

import com.obtk.entitys.UserEntity;

public class BeforAdvise implements MethodBeforeAdvice{
	@Override
	public void before(Method arg0, Object[] arg1, Object arg2)
			throws Throwable {
		UserEntity user=(UserEntity)arg1[0];
		user.setEmail("1111111111");
		System.out.println("在调用"+arg2+"的方法"+arg0.getName()+"之前调用了这里的代码"
				+",方法的参数:"+Arrays.toString(arg1));
	}
}

测试类

========TestAop1.java=====

package com.obtk.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.obtk.dao.IUserDao;
import com.obtk.entitys.UserEntity;


public class TestAop1 {
	public static void main(String[] args) {
		ApplicationContext ctx=
			new ClassPathXmlApplicationContext("ApplicationContext.xml");
		IUserDao userDao=(IUserDao)ctx.getBean("userDao");
		UserEntity user=new UserEntity("mike", "123", "mike@qq.com");
		userDao.saveUser(user);
	}
}

三   关于切入点的配置

1. 最明确的写法
execution(public int com.obtk.dao.UserDaoImpl.saveUser(com.obtk.entitys.UserEntity))
2   【..】表示匹配方法里面的任意参数类型及个数
execution(public int com.obtk.dao.UserDaoImpl.saveUser(..))
3.  *表示匹配dao层下面所要类
execution(public int com.obtk.dao.*.saveUser(..))
4.  表示匹配dao层下面所有类的所有返回int方法
execution(public int com.obtk.dao.*.*(..))
5.  表示匹配dao层下面所有类的所有返回任意类型方法
execution(* com.obtk.dao.*.*(..))
6.  表示匹配dao层下面所有的类及其子包的类里面的所有返回任意类型方法
execution(* com.obtk.dao..*.*(..))









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

御前两把刀刀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值