- spring aop
面向切面编程(AOP),是软件编程思想发展到一定阶段的产物,是对面向对象编程(OOP)的有益补充。AOP一般适用于具有横切逻辑的场合,如访问控制、事务管理、性能监测等。
面向切面编程,简单的说,就是在不改变源程序的基础上为代码段增加新的功能,对代码进行增强处理,它的设计思想来源于代理设计模式。
了解之后需要知道以下概念:
1.增强类型:
前置增强(通知),在在原方法执行之前进行处理,同理还有后置增强、环绕增强、异常抛出增强、最终增强等。
2.连接点(Joinpoint):
程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。
3.切点(Pointcut):
每个类都拥有多个连接点:类的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。
需求:UserDao 接口(根据id 获取用户信息)
/**
* @note 用户Dao
* @author liuh
* */
public interface UserDao {
/**
* @note 根据用户id 获取用户
* @author liuh
* */
public User getUser(int id);
}
UserDaoImpl 实现
/**
* @note 用户UserDao 接口实现
* @author liuh
* */
public class UserDaoImpl implements UserDao{
/**
* @note 根据id 获取用户
* @author liuh
* */
@Override
public User getUser(int id){
System.out.println("模拟根据【id】获取用户信息实现");
User u=new User();
u.setId(id);
u.setName("hello");
return u;
}
}
- 基于xml配置实现spring aop增强
1.前置增强
(1)创建UserLogger类,新增before_log方法:
/**
* @note 用户增强类
* @author liuh
* */
public class UserLogger {
/**
* @note 前置
* */
public void before_log(JoinPoint jp){
System.out.println("调用"+jp.getTarget()+"的方法:"+jp.getSignature().getName()+"参数:"+jp.getArgs());
}
}
(2)配置增强实现
<!-- 用户Dao 实现Bean -->
<bean id="aop_userImpl" class="com.liuh.aop.UserDaoImpl"></bean>
<!-- 用户增强 实现 Bean -->
<bean id="use_log" class="com.liuh.aop.UserLogger"></bean>
<!-- aop stat -->
<aop:config>
<!-- 切点 -->
<aop:pointcut expression="execution(public * getUser(..))" id="useDao_point"/>
<!-- 增强 -->
<aop:aspect ref="use_log">
<!-- 前置增强 -->
<aop:before method="before_log" pointcut-ref="useDao_point"/>
</aop:aspect>
</aop:config>
<!-- aop end -->
2.后置增强
(1)在新增UserLogger类 afterReturn_log方法
/**
* @note 后置返回值
* */
public void afterReturn_log(JoinPoint jp,Object obj){
System.out.println("调用"+jp.getTarget()+"的方法:"+jp.getSignature().getName()+"参数:"+jp.getArgs()+"返回值:"+((User)obj).getName());
}
(2)后置增强配置
<!-- 用户Dao 实现Bean -->
<bean id="aop_userImpl" class="com.liuh.aop.UserDaoImpl"></bean>
<!-- 用户增强 实现 Bean -->
<bean id="use_log" class="com.liuh.aop.UserLogger"></bean>
<!-- aop stat -->
<aop:config>
<!-- 切点 -->
<aop:pointcut expression="execution(public * getUser(..))" id="useDao_point"/>
<!-- 增强 -->
<aop:aspect ref="use_log">
<!-- 后置增强 返回值 -->
<aop:after-returning method="afterReturn_log" pointcut-ref="useDao_point" returning="obj"/>
</aop:aspect>
</aop:config>
<!-- aop end -->
3.环绕增强
(1)在新增UserLogger类 round_log方法
/**
* @note 环绕
* */
public void round_log(ProceedingJoinPoint jp){
System.out.println("前置调用"+jp.getTarget()+"的方法:"+jp.getSignature().getName()+"参数:"+jp.getArgs());
Object obj=null;
try {
obj =jp.proceed();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("后置调用"+jp.getTarget()+"的方法:"+jp.getSignature().getName()+"参数:"+jp.getArgs()+"返回值:"+((User)obj).getId());
}
(2)环绕配置
<!-- 用户Dao 实现Bean -->
<bean id="aop_userImpl" class="com.liuh.aop.UserDaoImpl"></bean>
<!-- 用户增强 实现 Bean -->
<bean id="use_log" class="com.liuh.aop.UserLogger"></bean>
<!-- aop stat -->
<aop:config>
<!-- 切点 -->
<aop:pointcut expression="execution(public * getUser(..))" id="useDao_point"/>
<!-- 增强 -->
<aop:aspect ref="use_log">
<!-- 环绕 -->
<aop:around method="round_log" pointcut-ref="useDao_point"/>
</aop:aspect>
</aop:config>
<!-- aop end -->
4.异常增强(异常抛出增强方法)
(1)在新增UserLogger类 catch_log方法
/**
* @note 异常增强
* */
public void catch_log(JoinPoint jp,RuntimeException e){
try {
throw e;
} catch (Exception e2) {
System.out.println("处理该异常");
// TODO: handle exception
}
System.out.println("异常调用"+jp.getTarget()+"的方法:"+jp.getSignature().getName()+"参数:"+jp.getArgs()+"异常:"+e.getMessage());
}
(2)异常增强配置
<!-- 用户Dao 实现Bean -->
<bean id="aop_userImpl" class="com.liuh.aop.UserDaoImpl"></bean>
<!-- 用户增强 实现 Bean -->
<bean id="use_log" class="com.liuh.aop.UserLogger"></bean>
<!-- aop stat -->
<aop:config>
<!-- 切点 -->
<aop:pointcut expression="execution(public * getUser(..))" id="useDao_point"/>
<!-- 增强 -->
<aop:aspect ref="use_log">
<!-- 异常增强 -->
<aop:after-throwing method="catch_log" pointcut-ref="useDao_point" throwing="e"/>
</aop:aspect>
</aop:config>
<!-- aop end -->
5.最终增强
我们知道,如果在目标方法中抛出了异常,就不会执行后续的后置增强。在AspectJ中为我们提供了一种最终增强,无论是否出了异常都会执行,类似于try-catch中的finally块,一般用于释放资源
(1)在新增UserLogger类 after_log方法
/**
* @note 最终
* */
public void after_log(JoinPoint jp){
System.out.println("最终增强调用"+jp.getTarget()+"的方法:"+jp.getSignature().getName()+"参数:"+jp.getArgs());
}
(2)最终增强配置
<!-- 用户Dao 实现Bean -->
<bean id="aop_userImpl" class="com.liuh.aop.UserDaoImpl"></bean>
<!-- 用户增强 实现 Bean -->
<bean id="use_log" class="com.liuh.aop.UserLogger"></bean>
<!-- aop stat -->
<aop:config>
<!-- 切点 -->
<aop:pointcut expression="execution(public * getUser(..))" id="useDao_point"/>
<!-- 增强 -->
<aop:aspect ref="use_log">
<!-- 最终增强 -->
<aop:after method="after_log" pointcut-ref="useDao_point"/>
</aop:aspect>
</aop:config>
<!-- aop end -->
- 测试
public class AopTest {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userD=(UserDao)ctx.getBean("aop_userImpl");
userD.getUser(1123);
}
}