首先我们先来介绍一下AOP:

AOP(Aspect Orient Programming),面向切面编程,是面向对象编程OOP的一种补充。面向对象编程是从静态角度考虑程序的结构,面向切面编程是从动态的角度考虑程序运行过程。

AOP底层,就是采用动态代理模式实现的。采用两种代理:JDK的动态代理,与CGLIB的动态代理。JDK的动态代理是面向接口的,CGLIB既可以实现有接口的,又可以实现没有接口的。(对动态代理不了解的可以看看我的其关于动态代理的介绍)

面向切面编程,就是将交叉业务逻辑封装成切面,利用AOP容器的功能将切面植入到主业务逻辑中。所谓交叉业务逻辑是指:通用的,与主业务逻辑无关的代码,如安全检查,事务日志等。

Spring的AOP的几种用法:

通知:即我们的切面方法

  1. 前置通知
  2. 后置通知
  3. 环绕通知
  4. 异常通知

(一)前置通知

所谓前置通知,就是这个切面方法在我们的主业务方法之前执行。

首先我们先写一个目标接口:

//目标接口
public interface SomeServices {
String doFirst();
void doSecond();
}

//接口实现类,也就是主业务方法类
public class SomeServiceImp implements SomeServices{ @Override
public String doFirst() {
System.out.println("print first");
return null;
}
@Override
public void doSecond() {
System.out.println("print second");
}
}

//切面方法,需要实现:**MethodBeforeAdvice** 接口
public class myBeforeMethodAdvice implements MethodBeforeAdvice { //method:业务方法
//args:方法参数
//target:目标类
@Override
public void before(Method method, Object[] arg1, Object target) throws Throwable {
System.out.println("执行主业务前方法");
} }

<!--Spring主配置文件-->
<bean id="service" class="com.test.beforeMethodAdvice.SomeServiceImp"/> <bean id="myAdvice" class="com.test.beforeMethodAdvice.myBeforeMethodAdvice"/> <bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="service"/>
<!--<property name="target" value="service"/>-->
<property name="interceptorNames" value="myAdvice"/>
</bean>

接着是测试方法:

public class test {

	@Test
public void Test01() {
String source = "com/test/beforeMethodAdvice/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(source);
SomeServices service = (SomeServices)ac.getBean("ProxyService");
service.doFirst();
service.doSecond();
}
}
//控制台输出:
//执行主业务前方法
//print first
//执行主业务前方法
//print second

(二)后置通知

后置通知和前置通知雷同,只是切面方法的实现类不同,但是后置通知实现接口方法,多给用了一个returnValue参数,也就意味着我们可以获得主业务方法的返回值,我们来看看范例:

//主业务接口
public interface SomeServices {
String doFirst();
void doSecond();
}

//主业务方法实现类,doFirst()有返回值
package com.test.afterMethodAdvice; public class SomeServiceImp implements SomeServices{
@Override
public String doFirst() {
System.out.println("print first");
return "abc";
}
@Override
public void doSecond() {
System.out.println("print second");
}
}

//实现了**AfterReturningAdvice** 接口,实现这个接口的方法有一个返回值参数
public class myAfterMethodAdvice implements AfterReturningAdvice {
//returnValue:业务方法的返回值
//method:业务方法属性类
//args:方法参数
//target:目标类
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行业务后方法");
//只能获取到业务方法的返回值,但是不能进行修改
System.out.println(returnValue);
}
}

<!--配置文件没什么差别-->
<bean id="service" class="com.test.afterMethodAdvice.SomeServiceImp"/> <bean id="myAdvice" class="com.test.afterMethodAdvice.myAfterMethodAdvice"/> <bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="service"/>
<!--<property name="targetName" value="service"/>-->
<property name="interceptorNames" value="myAdvice"/>
</bean>

测试方法:

public class test {
@Test
public void Test01() {
String source = "com/test/afterMethodAdvice/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(source);
SomeServices service = (SomeServices)ac.getBean("ProxyService");
service.doFirst();
service.doSecond();
}
}
//print first
//执行业务后方法
//abc
//print second
//执行业务后方法
//null

(三)环绕通知

环绕通知就是既能实现前置通知又能实现后置通知,但是不同的是它能够对主业务方法进行修改。

//主业务接口
public interface SomeServices {
String doFirst();
void doSecond();
}

//主业务方法实现类
public class SomeServiceImp implements SomeServices{
@Override
public String doFirst() {
System.out.println("print first");
return "abc";
}
@Override
public void doSecond() {
System.out.println("print second");
}
}

//环绕通知,切面方法类,需要实现**MethodInterceptor**
//并且调用参数的proceed方法,这个方法有一个返回值,也就是主业务方法的返回值,我们可以对它进行修改。
public class MyMethodInterceptor implements MethodInterceptor { @Override
public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("环绕通知,业务方法前");
Object result = invocation.proceed();
System.out.println("环绕通知,业务方法后");
if(result != null) {
result = ((String)result).toUpperCase();
}
return result;
}
}

//环绕通知的配置文件
<bean id="service" class="com.test.MethodInterceptor.SomeServiceImp"/> <bean id="myAdvice" class="com.test.MethodInterceptor.MyMethodInterceptor"/> <bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="service"/>
<property name="interceptorNames" value="myAdvice"/>
</bean>

//测试方法:
public class test { @Test
public void Test01() {
String source = "com/test/MethodInterceptor/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(source);
SomeServices service = (SomeServices)ac.getBean("ProxyService");
String result = service.doFirst();
System.out.println(result);
service.doSecond(); }
}
//控制台输出:
//环绕通知,业务方法前
//print first
//环绕通知,业务方法后
//ABC
//环绕通知,业务方法前
//print second
//环绕通知,业务方法后

(四)异常通知:

异常通知就是当我们的主业务方法出现异常的时候,会对这个主业务方法进行加强!

例如:我们现在的主业务方法是对用户名和密码进行判断,如果用户名或者密码有误,我们就就分别抛出对应的错误,当无误的时候,程序正常执行。


//主业务接口,判断用户名,密码是否正确
public interface SomeServices {
boolean checkedUser(String username,String password) throws UserException;
}

//实现类,实现了对用户和密码的校验
public class SomeServiceImp implements SomeServices{ @Override
public boolean checkedUser(String username, String password)throws UserException { if(!"admin".equals(username.trim())) {
throw new UsernameException("用户名错误");
}
if(!"123".equals(password.trim())){
throw new PasswordException("密码错误");
}
return true;
}
}

上面两个是我们需要的主业务方法,里面我们定义了两个异常:UsernameException,PasswordException,它们都实现了父类UserException:


//UserException
public class UserException extends Exception { public UserException() {
super();
}
public UserException(String message) {
super(message);
}
}

//UsernameException
public class UsernameException extends UserException { public UsernameException() {
super();
} public UsernameException(String message) {
super(message);
}
}

//PasswordException
public class PasswordException extends UserException { public PasswordException() {
super();
} public PasswordException(String message) {
super(message);
} }

定义好上面的异常后我们就要定义我们的通知类了:

//这个异常通知需要实现ThrowsAdvice接口,接口源码上面有,我们追踪到源码会发现这个接口没有需要实现的方法,其实是由几个供我们选择,防止我们没有必要的实现全部方法

public class MyThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(Exception ex) {
System.out.println("执行异常通知方法:" + ex.getMessage());
}
}

配置文件没有什么变化:

<bean id="service" class="com.test.afterExceptionAdvice.SomeServiceImp"/>

	<bean id="myAdvice" class="com.test.afterExceptionAdvice.MyThrowsAdvice"/>

	<bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="service"/>
<property name="interceptorNames" value="myAdvice"/>
</bean>

最后就是我们的测试方法:

public class test {

	@Test
public void Test01() {
String source = "com/test/afterExceptionAdvice/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(source);
SomeServices service = (SomeServices)ac.getBean("ProxyService");
//service.checkedUser("admin", "123");
//service.checkedUser("ad", "123");
try {
service.checkedUser("admin", "12");
} catch (UserException e) {
e.printStackTrace();
}
}
}
//控制台:
//**报错**
//执行异常通知方法:密码错误

本篇文章可能主要是代码的实现,原理上没有说的太多,因为前面关于动态代理的文章我也写了一篇,所以这里就没有赘述太多动态代理的知识。

本篇文章文章就介绍到这里,如有错误不吝赐教!

下一篇:AOP高级用法

08 Spring框架 AOP (一)的更多相关文章

  1. spring框架 AOP核心详解

    AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Asp ...

  2. 跟着刚哥学习Spring框架--AOP(五)

    AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入 ...

  3. spring框架aop用注解形式注入Aspect切面无效的问题解决

    由于到最后我的项目还是有个邪门的错没解决,所以先把文章大概内容告知: 1.spring框架aop注解扫描默认是关闭的,得手动开启. 2.关于Con't call commit when autocom ...

  4. Spring框架——AOP代理

    我们知道AOP代理指的就是设计模式中的代理模式.一种是静态代理,高效,但是代码量偏大:另一种就是动态代理,动态代理又分为SDK下的动态代理,还有CGLIB的动态代理.Spring AOP说是实现了AO ...

  5. Spring框架-AOP详细学习[转载]

    参考博客:https://blog.csdn.net/qq_22583741/article/details/79589910#4-%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85% ...

  6. Spring框架 AOP面向切面编程(转)

    一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...

  7. 10 Spring框架 AOP (三) Spring对AspectJ的整合

    上两节我们讲了Spring对AOP的实现,但是在我们的开发中我们不太使用Spring自身的对AOP的实现,而是使用AspectJ,AspectJ是一个面向切面的框架,它扩展了Java语言.Aspect ...

  8. 09 Spring框架 AOP (二) 高级用法

    上一篇文章我们主要讲了一点关于AOP编程,它的动态考虑程序的运行过程,和Spring中AOP的应用,前置通知,后置通知,环绕通知和异常通知,这些都是Spring中AOP最简单的用法,也是最常用的东西, ...

  9. Spring框架AOP学习总结(下)

    目录 1. AOP 的概述 2. Spring 基于AspectJ 进行 AOP 的开发入门(XML 的方式): 3.Spring 基于AspectJ 进行 AOP 的开发入门(注解的方式): 4.S ...

随机推荐

  1. GridView解决同一行item的高度不一样,如何同一行统一高度问题?

    问题描述: 有时我们使用GridView会面对类似这种情况. 这是是不是一脸愣逼,我们理想情况是把他变成这样 保证同一行的item都是一样高这样就美观许多了 注意:上面的两张图片是盗图,用来作为效果观 ...

  2. JMeter基础之-使用技巧

    在这此对新版本jmeter的学习+温习的过程,发现了一些以前不知道的功能,所以,整理出来与大分享.本文内容如下. 如何使用英文界面的jmeter 如何使用镜像服务器 Jmeter分布式测试 启动Deb ...

  3. 安装python各类工具包、IDE以及著名开源模块如kaldi等的简单总结

    在学习一门语言或者使用一个著名的开源工具时,搭建环境是非常重要的一步,在环境搭建的过程中往往要踩很多坑.昨天一不小心把电脑操作系统整坏了,搞了个通宵算是搞定了,把win10系统重装回win7,但之前搭 ...

  4. ORB特征提取与匹配

    ORB特征是目前最优秀的特征提取与匹配算法之一,下面具体讲解一下: 特征点的检测 图像的特征点可以简单的理解为图像中比较显著显著的点,如轮廓点,较暗区域中的亮点,较亮区域中的暗点等.ORB采用FAST ...

  5. iOS - 导航栏UINavigationController经常使用属性

    1.设置导航栏标题 self.title = @"dylan_李伟宾"; 2.设置导航栏样式 设置方法: [self.navigationController.navigation ...

  6. Eclipse虚拟内存不足【Eclipse中虚拟内存设置】

    Eclipse最近在做J2EE项目中 发现老是出现虚拟内存不足的提示 前2天去加了根内存 问题同样存在 为了让我在写代码时 不在出现那讨厌的内存不足的提示 也为了 不让那破机器再卡住 今天找到了解决方 ...

  7. python 之 多线程

    一.多线程(具体可参照博文多进程---->http://www.cnblogs.com/work115/p/5621789.html) 1.函数式实现多线程 2.类实现多线程 3.多线程之线程锁 ...

  8. [HEOI2015]兔子与樱花[贪心]

    4027: [HEOI2015]兔子与樱花 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1043  Solved: 598[Submit][Stat ...

  9. 与Mysqli相关的四种数据库取值

    <!--取值方案一:通过数字数组 fetch_row()--><meta http-equiv="Content-Type" content="text ...

  10. matplotlib绘制圆饼图

    import matplotlib.pyplot as plt labels = ['Nokia','Samsung','Apple','Lumia'] values = [10,30,45,15] ...