08 Spring框架 AOP (一)

首先我们先来介绍一下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{@Overridepublic String doFirst() {System.out.println("print first");return null;}@Overridepublic void doSecond() {System.out.println("print second");}
}
//切面方法,需要实现:**MethodBeforeAdvice** 接口
public class myBeforeMethodAdvice implements MethodBeforeAdvice {//method:业务方法//args:方法参数//target:目标类
    @Overridepublic 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 {@Testpublic 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{@Overridepublic String doFirst() {System.out.println("print first");return "abc";}@Overridepublic void doSecond() {System.out.println("print second");}
}
//实现了**AfterReturningAdvice** 接口,实现这个接口的方法有一个返回值参数
public class myAfterMethodAdvice implements AfterReturningAdvice {//returnValue:业务方法的返回值//method:业务方法属性类//args:方法参数//target:目标类
    @Overridepublic 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 {@Testpublic 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{@Overridepublic String doFirst() {System.out.println("print first");return "abc";}@Overridepublic void doSecond() {System.out.println("print second");}
}
//环绕通知,切面方法类,需要实现**MethodInterceptor** 
//并且调用参数的proceed方法,这个方法有一个返回值,也就是主业务方法的返回值,我们可以对它进行修改。
public class MyMethodInterceptor implements MethodInterceptor {@Overridepublic 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 {@Testpublic 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{@Overridepublic 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 {@Testpublic 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();}}
}
//控制台:
//**报错**
//执行异常通知方法:密码错误

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

 

 

 

 

版权声明:本文为博主原创文章,如需转载请表明出处。 https://blog.csdn.net/qq_39266910/article/details/78742552 

 

转载于:https://www.cnblogs.com/chengshun/p/9776849.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367035.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

移动spa商城优化记(一)---首屏优化篇

背景 随着公司业务的不断壮大&#xff0c;最近老是有用户反应公司APP内的商城打开比较慢&#xff0c;这可不行啊&#xff0c;慢了容易流失用户&#xff0c;流失用户减少公司业绩&#xff0c;公司业绩少我的年终奖就少…………&#xff0c;所以为了公司&#xff0c;也为了自己&a…

hprose for java 教程_hprose for java源码分析-4

4.1 疑窦丛生书接上回。上回说到&#xff0c;从HproseClient.java ------------------------- (#0)invokeHandler.handle()开始&#xff0c;将经历一个漫长的调用过程&#xff0c;下面把整个调用链粘出来&#xff0c;先认识下这个庞然大物。( >>> 表示调用到&#xff…

java批量提取文件夹名称_bat 批量提取指定目录下的文件名

bat 批量提取指定目录下的文件名下面是批量获取指定目录下的文件名的核心代码echo offecho text inputset inputset /p input:echo %input% is inputcd %input%rem echo onfor %%a in (*) do (echo %%a is input)cd ..如下是sql server执行对应脚本文件sqlcmd -Spcserver -dmas…

埃及分数The Rotation Game骑士精神——IDA*

IDA*&#xff1a;非常好用的搜索&#xff0c;可以解决很多深度浅&#xff0c;但是规模大的搜索问题。 估价函数设计思路&#xff1a;观察一步最多能向答案靠近多少。 埃及分数 题目大意&#xff1a; 给出一个分数&#xff0c;由分子a 和分母b 构成&#xff0c;现在要你分解成一…

美团扫码付的前端可用性保障实践

开篇 2017年&#xff0c;美团金融前端遇到了很多通用性问题&#xff0c;特别是在保障前端可用性的过程中&#xff0c;我们团队也踩了不少“坑”&#xff0c;在梳理完这些问题以后&#xff0c;我们还专门做了第31期线下沙龙给大家进行了分享。不管是在面试过程中与候选人讨论&a…

Servlet上传文件和下载文件示例

Java Web应用程序中的文件上载和下载以及常见任务。 由于最近我写了很多有关Java servlet的文章 &#xff0c;因此我想提供一个使用servlet上传和下载文件的示例示例。 用例 我们的用例是提供一个简单HTML页面&#xff0c;客户端可以在其中选择要上传到服务器的本地文件。 在提…

java创建异步多线程_Java创建多线程异步执行实现代码解析

实现Runable接口通过实现Runable接口中的run()方法public class ThreadTest implements Runnable {public static void main(String[] args) {Thread thread new Thread(new ThreadTest());thread.start();}Overridepublic void run() {System.out.println("Runable 方式…

hive基本操作与应用

通过hadoop上的hive完成WordCount 启动hadoop Hdfs上创建文件夹 上传文件至hdfs 启动Hive 创建原始文档表 导入文件内容到表docs并查看 用HQL进行词频统计&#xff0c;结果放在表word_count里 查看统计结果 转载于:https://www.cnblogs.com/cairuiqi/p/9048256.html

Apache log4j是领先的日志记录框架

根据 从零周转开始的调查中&#xff0c; Apache log4j是领先的Java日志记录框架。 这实际上是一个非常有趣的调查。 它显示SLF4J最常用作伐木外墙&#xff0c;占61&#xff05;。 但是&#xff0c;它似乎最常与Apache Log4j一起使用&#xff0c;52&#xff05;的调查参与者都…

Centos6.8通过yum安装mysql5.7

Centos6.8通过yum安装mysql5.7 2017年07月13日 14:19:10 阅读数&#xff1a;1067 1.安装mysql的yum源 a.下载配置mysql的yum源的rpm包 根据上面3张图片中的操作下载下来的rpm文件可以通过如下命令获取&#xff1a; wget https://dev.mysql.com/get/mysql57-community-release-e…

Mvc+Hui+SqlSugar+Autofac+NLog+T4 架构设计(一)

一、前言 作为小菜鸟第一次写博客的我还有点小激动&#xff0c;最近开始打算着手写一个属于自己架构。算下来差不多最近花一周多的下班时间了来写这个框架&#xff0c;本来想整体架构开发完成测试完成后才写博客&#xff0c;怕自己没时间或失去动力&#xff0c;就先把自己架构设…

房价在手,天下我有 --反手就撸一个爬虫(终)

接上篇&#xff0c;科科&#xff0c;好&#xff0c;我们继续 我们在这里先把json数据入库吧&#xff5e; 首先&#xff0c;database/scheme里定义好数据类型。 const mongoose require(mongoose)const detailHouseSchema new mongoose.Schema({ //定义数据模式link:String…

Spring MVC:带有CNVR卷的REST应用程序。 1个

不久前&#xff0c;我阅读了Paul Chapman撰写的有关内容协商视图解析器 &#xff08;CNVR&#xff09;的文章。 Spring Framework Blog上的那篇文章启发了我研究这个框架的领域。 因此&#xff0c;我开发了一个基于Spring MVC和CNVR的 REST示例应用程序。 该应用程序演示了REST…

《精通Spring 4.x 企业应用开发实战》学习笔记

第四章 IoC容器 4.1 IoC概述 IoC&#xff08;Inverse of Control 控制反转&#xff09;&#xff0c;控制是指接口实现类的选择控制权&#xff0c;反转是指这种选择控制权从调用类转移到外部第三方类或容器的手中。 也就是由Spring容器借由Bean配置来进行控制。 DI&#xff08;D…

微前端——无界wujie

B站课程视频 课程视频 课程课件笔记&#xff1a; 1.微前端 2.无界 现有的微前端框架&#xff1a;iframe、qiankun、Micro-app&#xff08;京东&#xff09;、EMP&#xff08;百度&#xff09;、无届 前置 初始化 新建一个文件夹 1.通过npm i typescript -g安装ts 2.然后可…

java executor spring_Spring+TaskExecutor实例

一 TaskExecutor接口Spring的TaskExecutor接口等同于Java.util.concurrent.Executor接口。 实际上&#xff0c;它存在的主要原因是为了在使用线程池的时候&#xff0c;将对Java 5的依赖抽象出来。 这个接口只有一个方法execute(Runnable task)&#xff0c;它根据线程池的语义和…

小程序居然可以用WXS模拟实现过滤器!

小程序目前官方还没有出过滤器&#xff0c;特别不方便&#xff0c;但是可以用wxs来模拟过滤器&#xff0c;话不多说&#xff0c;直接上代码。当然&#xff0c;不熟悉wxs的可以先看一下 官方文档 1.新建一个filter.wxs的文件我个人建议是一个过滤器写一个wxs&#xff0c;避免引用…

ADF:使用HTTP POST方法进行URL任务流调用

众所周知&#xff0c;可以通过某些URL直接从浏览器或某些外部应用程序调用有限任务流。 如果任务流的属性“ URL invoke”设置为“ url-invoke-allowed”&#xff0c;则启用此功能&#xff0c;该功能通常在集成项目中使用。 通常&#xff0c;客户端&#xff08;或调用者&#x…

java 项目做多级缓存_【开源项目系列】如何基于 Spring Cache 实现多级缓存(同时整合本地缓存 Ehcache 和分布式缓存 Redis)...

一、缓存当系统的并发量上来了&#xff0c;如果我们频繁地去访问数据库&#xff0c;那么会使数据库的压力不断增大&#xff0c;在高峰时甚至可以出现数据库崩溃的现象。所以一般我们会使用缓存来解决这个数据库并发访问问题&#xff0c;用户访问进来&#xff0c;会先从缓存里查…

Spring MVC:带有CNVR卷的REST应用程序。 3

这是带有CNVR的Spring MVC REST教程的最后一部分。 在这里&#xff0c;我将演示所有这些东西如何工作&#xff0c;这是我在前两部分中开发的。 对于每种类型的CRUD操作&#xff0c;这将分为四个部分&#xff1a;CREATE&#xff0c;READ&#xff0c;UPDATE&#xff0c;DELETE。 …