Spring面向方面的编程

介绍

在理想的面向对象系统中,我们希望将每个对象设计为执行一项特定任务。 但是,除了执行其主要任务外,对象还执行被动任务,例如日志记录,事务,安全性,缓存等。这些被动活动是必需的,但不是业务逻辑的一部分,被称为“ 跨切问题 ”。

(横切关注点==系统中常用的功能)

横切关注点与业务逻辑分开可能是编写精心设计的解耦代码的重要一步。 让我们思考一下解决交叉切割问题的方法

遗产

继承立即在脑海中弹出,我们可以继承通用功能并在对象中使用它。 但是继承通用功能需要我们设计一个基类。 如果我们在多个地方重用该类,那么以后修改类可能会很困难。

继承==以后很难修改(非弹性代码)

代表团

委派是处理交叉切割问题的更好方法。 记住组成要重于继承,(授权和组成要共同关注)。 但是,那么我们将不得不在许多地方进行调用以委托对象,从而使其变得繁琐。

委派==繁琐

面向方面的编程

这是否意味着我们要喝汤了。 相反,这给我们提供了第三种也是最好的方法,即面向方面的编程。 AOP避免了继承的脆弱性和委派的繁琐性。 AOP在相互交叉的关注点领域大放异彩

什么是AOP?

AOP允许我们将横切关注点模块化到称为Aspects的特殊对象中,从而创建更清晰和分离的代码。 有了适当的方面,对象就不必担心执行被动横切问题,因为AOP会处理所有这些问题。

与AOP有关的术语

像任何成功的技术一样,AOP也带有自己的术语和术语集。 让我们先看一下那些,然后再进行更深入的了解AOP的工作。

  1. 关注 –这些是基于其功能模块化的系统的一部分。 有两种类型的关注点。 1.核心关注点2.跨领域关注点。 核心关注点与系统的业务逻辑相关,即系统执行的主动任务,例如生成工资单,获取员工记录,进行银行转账等。跨部门关注点是执行主动任务(例如日志记录,缓存)所需的被动任务等等
  2. 连接点–连接点是执行流程中的一点,其中发生了一些动作,并且有可能应用Aspect(跨领域关注点)。 连接点可以是调用方法,引发异常或对象状态改变。
  3. 建议 – AOP中的每个方面都有其目的,即它必须完成的工作。 该作业必须在连接点处应用。 方面的工作或目的称为建议。 除了定义方面的工作之外,建议还定义方面执行工作的时间。 应该在核心任务完成执行之前或之后应用作业,还是在两者之前和之后应用作业。
  4. 切入点 –系统中可以有许多连接点,但是并非所有方面都由Aspect建议。 Aspect从Pointcut获得帮助,以选择要在其中编织建议的Joinpoint。
  5. 方面 –建议和切入点定义了方面。 正如我们看到的,建议定义了方面的工作以及何时执行。 虽然Pointcut定义了方面编织建议的位置。 因此,工作的内容,时间和地点定义了方面。
  6. 目标 –目标是被建议的对象。 (核心关注)。 在AOP的帮助下,该对象可以自由地执行其主要任务,而不必担心交叉问题。
  7. 代理 –将建议应用于目标对象时,将创建一个代理对象。 AOP容器创建并管理对象的生命周期,程序员无需担心它们。
  8. 编织 –编织是将Advice或Aspect应用于目标对象以创建代理对象的过程。 编织可以在编译时或类加载时或在运行时完成。 通常,Spring AOP在运行时将方面编织到目标对象中。

那是要消化的一长串术语。 在继续之前,请花点时间了解它们。

咨询类型

沉迷于示例之前的最后一篇文章是学习建议的类型。 主要有4种建议。

  1. 建议之前 –在Joinpoint开始执行之前应用建议之前。 通过实现org.springframework.aop.MethodBeforeAdvice接口来创建BeforeAdvice。 要实现的方法是公共无效(方法m,对象args [],对象目标)抛出Throwable
  2. 返回建议之后–在Joinpoint完成执行之后应用建议之后。 AfterReturningAdvice是通过实现org.springframework.aop.AfterReturningAdvice接口创建的。 ThingableReturning(Method m,Object args [],Object target)抛出后 ,要实现的方法是公共无效
  3. 引发建议 –当Joinpoint在执行过程中引发异常时,将应用引发建议。
  4. 围绕建议 –此建议围绕Joinpoint执行,并在Joinpoint执行之前和之后执行。 这甚至可以用来控制Joinpoint的调用。

我们将尝试在SpringAOP的帮助下开发一个简单的缓存。 缓存具有三个主要的核心问题。

核心关注点

  1. 将对象保存在缓存中。
  2. 从缓存返回对象。
  3. 从缓存中删除对象。

现在,除了这些核心问题之外,缓存框架还有其他被动任务。 这些被动任务构成了交叉问题。

横切关注点

  1. 达到其大小限制时重新调整缓存大小。 (LRU)实施。
  2. 锁定对象以防止在读取对象时将其删除。
  3. 锁定高速缓存以防止在调整大小时阻止和读取/写入/删除高速缓存。

编码所有这些横切关注点可能是耗时且乏味的,因此让我们简化示例,当缓存已满时,我们将仅实现调整大小逻辑。 因此,在完成示例之后,我们将拥有一个可以放置,获取和删除对象的缓存。 例如,缓存的最大大小已设置为10。 一旦高速缓存存储了10个对象,则对高速缓存的任何添加都将导致通过删除第一个对象来删除(重新调整大小)高速缓存。 调整大小的操作由使用Spring AOP创建的Aspect控制。 这是示例中要遵循的步骤

可以从SVN此处下载示例代码: https : //www.assembla.com/code/weblog4j/subversion/nodes/31/SpringDemos/trunk

  1. 依赖关系 – AOP是spring的核心功能,因此要使Spring AOP正常运行,我们需要的是核心spring jar,因此在您的POM中添加以下依赖关系。
    <dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency>
  2. 核心缓存对象。
    package com.aranin.spring.aop;import java.util.Date;
    import java.util.LinkedHashMap;
    import java.util.Map;public class MyCache {private LinkedHashMap<String, Object> cacheMap = new  LinkedHashMap<String, Object>();private LinkedHashMap<String, Date> timeStampMap = new  LinkedHashMap<String, Date>();/*** defines the max size of hashmap*/private long maxsize = 10;  //should come from properties file or some configuration/*** how long the object should be stored before it is evicted from cache*/private long objectLifeTime = 10000;private boolean lock = false;public LinkedHashMap<String, Object> getCacheMap() {return cacheMap;}public void setCacheMap(LinkedHashMap<String, Object> cacheMap) {this.cacheMap = cacheMap;}public LinkedHashMap<String, Date> getTimeStampMap() {return timeStampMap;}public void setTimeStampMap(LinkedHashMap<String, Date> timeStampMap) {this.timeStampMap = timeStampMap;}public long getMaxsize() {return maxsize;}public void setMaxsize(long maxsize) {this.maxsize = maxsize;}public long getObjectLifeTime() {return objectLifeTime;}public void setObjectLifeTime(long objectLifeTime) {this.objectLifeTime = objectLifeTime;}public boolean isLock() {return lock;}public void setLock(boolean lock) {this.lock = lock;}/*** This method is used to retrive the object from cache* @param key* @return*/public Object get(String key){return this.getCacheMap().get(key);}/*** this method is used for putting an object in cache* @param key* @param object*/public void put(String key, Object object){//get the curr dateDate date = new Date(System.currentTimeMillis());//set object in cacheMapthis.getCacheMap().put(key,object);//put timestamp in cachethis.getTimeStampMap().put(key, date);}public void delete(String key){this.getCacheMap().remove(key);this.getTimeStampMap().remove(key);}public void clearAll(){this.setCacheMap(new  LinkedHashMap<String, Object>());this.setTimeStampMap(new  LinkedHashMap<String, Date>());}/*** remove last 2 entries* not worried about object life time* this is just an example*/public void resize(){System.out.println("inside resize");long size = this.getCacheMap().size();System.out.println("size + " + size);if(size == this.getMaxsize()){System.out.println("max size has reached");Map.Entry<String, Date> firstEntry = this.getTimeStampMap().entrySet().iterator().next();System.out.println("removing : " + firstEntry.getKey() + " value : " + firstEntry.getValue());this.timeStampMap.remove(firstEntry.getKey());Map.Entry<String, Object> firstCEntry = this.getCacheMap().entrySet().iterator().next();System.out.println("removing : " + firstCEntry.getKey() + " value : " + firstCEntry.getValue());this.cacheMap.remove(firstCEntry.getKey());}System.out.println("leaving resize with size : " + this.getCacheMap().size());}
    }

    这个课没什么好说的。 有两个LinkedHashMaps,一个用于存储对象,另一个用于存储将对象推入缓存时的时间戳。 最大大小设置为10,并且具有get,put和delete方法。 还有一个调整大小的方法,Aspect将调用此方法,稍后我们将进行检查。

  3. 调整建议
    package com.aranin.spring.aop;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;public class ResizeAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("invoking " + method.getName() + " on " + target.getClass() + " Object");if(method.getName().equals("put")){System.out.println("before invoking " + method.getName());((MyCache)target).resize();}}
    }

    如您所见,这是建议之前的一种方法。 类实现MethodBeforeAdvice接口,该接口包含单个方法before()。 如果您检查该方法,则在我们调用put方法时,将检查rezise方法是否被调用。

  4. Spring上下文springaopdemo.xml
    <?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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.1.xsd"><bean id="resizeAdvice" class="com.aranin.spring.aop.ResizeAdvice" /><bean id="myCache" class="com.aranin.spring.aop.MyCache" /><bean id="myAOPCache"class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="myCache" /><property name="interceptorNames"><list><value>resizeAdvice</value></list></property></bean>
    </beans>

    如果您注意到上述xml文件,则MyCache和ResizeAdvice都已注册为spring bean。 文件中的主要bean是myAOPCache。 这是spring aop在核心类上应用建议后创建的代理对象。 代理对象由ProxyFactoryBean类创建。 我们将myCache对象的引用传递给代理对象,并注册所有将应用于代理类的建议。

  5. 最后,让我们检查Client,这将有助于我们运行此演示。
    package com.aranin.spring.aop;import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.FileSystemXmlApplicationContext;public class MyCacheClient {public static void main(String[] args){ApplicationContext springcontext = new FileSystemXmlApplicationContext("D:/samayik/SpringDemos/src/main/resources/springaopdemo.xml");MyCache myCache = (MyCache)springcontext.getBean("myAOPCache");myCache.put("1", "1");myCache.put("2", "2");myCache.put("3", "3");myCache.put("4", "4");myCache.put("5", "5");myCache.put("6", "6");myCache.put("7", "7");myCache.put("8", "8");myCache.put("9", "9");myCache.put("10", "10");System.out.println((String)myCache.get("1"));System.out.println((String)myCache.get("2"));System.out.println((String)myCache.get("10"));myCache.put("11", "11");System.out.println((String)myCache.get("1"));System.out.println((String)myCache.get("2"));System.out.println((String)myCache.get("10"));System.out.println((String)myCache.get("11"));}}

    在该类中,我们启动spring容器并加载spingaopdemo.xml中存在的bean。 我们在缓存中推送10个对象,当我们尝试推送第11个对象时,第一个对象被删除并插入第11个对象。 输出很大,所以我没有发布输出。 上课并检查输出是否令您满意。

摘要

在这篇文章中,我们学习了如何使用面向方面的编程更好地处理交叉问题。 AOP是一个强大的概念,它使我们可以编写更清晰和更分离的代码。 AOP不提供任何新内容。 它所做的只是将业务逻辑与系统必须执行的其他普通任务分离。 它可以重用实现系统范围内交叉关注点的代码。 我们还学习了与AOP相关的各种术语。 最后但并非最不重要的一点是,我们看到了一个简单的示例,在该示例中,我们使用Spring AOP创建了一个简单的方法前建议,并将其应用于管理缓存系统。

注意

您可以自由使用和分发此代码中开发的缓存系统。 尽管不建议在生产系统中使用它。

一如既往,我一直希望这篇文章作为集体学习的启动平台,随意发表一两个关于您对AOP的看法以及如何计划在代码中使用它的评论。 祝您阅读愉快。

参考: Weblog4j博客上来自我们JCG合作伙伴 Niraj Singh的Spring面向方面编程 。

翻译自: https://www.javacodegeeks.com/2013/10/aspect-oriented-programming-with-spring-2.html

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

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

相关文章

vim ctags java源码_如何使用vim的插件Ctags查看Linux源码

一.ubuntu下安装Linux内核源码(1).查看自己的内核版本(2).查看源内的内核源码类表(3).下载源码(4).进入/usr/src(5).解压下载的文件到用户主二.安装vim插件Ctags和使用插件的介绍Ctags工具是用来遍历源代码文件生成tags文件&#xff0c;这些tags文件能被编辑器或其它工具用来快…

MySql - GROUP BY 和 HAVING关键字

本文主要针对GROUP BY 和 HAVING两个关键字进行分析 使用测试表如下&#xff1a; 测试前&#xff0c;只知道GROUP BY 这个关键字的作用是根据一个字段进行分组&#xff0c;去重。HAVING对分组设置条件。 具体分组规则&#xff0c;设置条件不清楚。 测试开始 首先 单独使用GROUP…

javascript引擎工作原理

1. 什么是JavaScript解析引擎&#xff1f; 简单地说&#xff0c;JavaScript解析引擎就是能够“读懂”JavaScript代码&#xff0c;并准确地给出代码运行结果的一段程序。比方说&#xff0c;当你写了 var a 1 1; 这样一段代码&#xff0c;JavaScript引擎做的事情就是看懂&#…

浏览器缓存原理以及本地存储

作为一名前端工作人员&#xff0c;前端的缓存知识是必须掌握的&#xff0c;因为一个网站打开网页的速度直接关系到用户体验&#xff0c;用户粘度&#xff0c;而提高网页的打开速度有很多方面需要优化&#xff0c;其中比较重要的一点就是利用好缓存&#xff0c;缓存文件可以重复…

linux shell 宏定义_linux内核修炼之系统调用

fork()这个系统调用是有两个返回值的&#xff0c;在子进程中的返回值是0&#xff0c;在父进程中的返回值是PID&#xff0c;如下图 fork一次 返回两次关于0x80中断和特权级检查在mian函数的sched_init()函数中调用宏&#xff1a;set_system_gate(0x80,&system_call);将0x80号…

使用JPA和Hibernate有效删除数据

您可能会遇到必须对关系数据库中存储的大量数据集执行批量删除的情况。 如果您将JPA与Hibernate一起用作基础OR映射器&#xff0c;则可以尝试通过以下方式调用EntityManager的remove&#xff08;&#xff09;方法&#xff1a; public void removeById(long id) {RootEntity ro…

java21个知识点重点_java21个知识点重点

http://blog.csdn.net/jerroluo/article/details/520025851. JVM相关(包括了各个版本的特性)对于刚刚接触Java的人来说&#xff0c;JVM相关的知识不一定需要理解很深&#xff0c;对此里面的概念有一些简单的了解即可。不过对于一个有着3年以上Java经验的资深开发者来说&#xf…

Django模型中字段属性choice使用

今天设计models时&#xff0c;用到了choice这个属性&#xff0c;用来限制用户做出选择的范围。比如说性别的选择&#xff08;男或女&#xff09;。 class User&#xff08;AbstractUser&#xff09;&#xff1a;。。。sex models.CharField(verbose_name性别,max_length5,choi…

面试题4,打印出100-999所有的“水仙花数”。

提示&#xff1a;水仙花数是指一个 n 位数 ( n≥3 )&#xff0c;它的每个位上的数字的 n 次幂之和等于它本身。 &#xff08;例如&#xff1a;1^3 5^3 3^3 153&#xff09; package 面试;/*** 水仙花数* author liugang* create 2018/12/19 20:07**/ public class Shuixianhu…

angularjs的$http请求方式

/*$http常用的几个参数$http服务的设置对象:1、method 字符串 表示发送的请求类型 get post jsonp等等2、url 字符串 绝对或者相对的URL,请求的目标3、params 字符串或对象 会被转化成查询字符串加到URL后面&#xff0c;如果不是字符串会被JSON序列化4、data 字符串或者对象 这…

response对象设置返回状态_postman 设置全局变量

postman大家都知道是一个测试接口的工具&#xff0c;也是目前比较流行的一种测试工具&#xff0c;但是postman只是用来将API地址和参数填入send一下就完了吗&#xff1f;其实不是&#xff0c;关于postman其实有很多玩法&#xff0c;对于测试来说我觉得掌握了postman是非常有必要…

测试过大输入的代码

在编写单元测试时&#xff0c;我们主要关注业务的正确性。 我们将竭尽所能&#xff0c;开开心心地走在最前沿。 我们有时会进行微基准测试并衡量吞吐量。 但是经常遗漏的一个方面是当输入过大时我们的代码如何表现&#xff1f; 我们测试了如何处理正常的输入文件&#xff0c;格…

资源不在java项目和构建路径上_编译单元不在Java项目的构建路径上-Maven

今天,我已经在日食中导入了一个Maven项目.当我尝试自动建议时,当我添加一些代码时,它提示我“编译单元不在Java项目的构建路径上”.我没有看到解决此问题的方法,但是都没有解决.这个应该做什么&#xff1f;xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://m…

Django 第八课 2.【MySQL相关软件 mysqlclient Navicat Premium】

MySQL 驱动程序安装&#xff1a; 我们使用 Django 来操作 MySQL&#xff0c;实际上底层还是通过 Python来操作的。因此我们想要用 Django 来操作 MySQL&#xff0c;首先还是需要安装一个驱动程序。在python3中&#xff0c;驱动程序有多种选择。比如pymysql 以及mysqlclient等。…

查看串口的驱动信息

1、查看串口的驱动信息 2、驱动安装文件&#xff1a;http://www.wch.cn/download/CH341SER_EXE.html 3、参考驱动资料:https://blog.csdn.net/jazzsoldier/article/details/70169732 转载于:https://www.cnblogs.com/qy1234/p/10146303.html

用jQuery监听浏览器窗口的变化

1 $(window).resize(function () { //当浏览器大小变化时 2 alert($(window).height()); //浏览器时下窗口可视区域高度 3 alert($(document).height()); //浏览器时下窗口文档的高度 4 alert($(document.body).height()); //浏览器时下…

java中怎么判断一段代码时线程安全还是非线程安全_Java 中的多线程你只要看这一篇就够了...

引如果对什么是线程、什么是进程仍存有疑惑&#xff0c;请先Google之&#xff0c;因为这两个概念不在本文的范围之内。用多线程只有一个目的&#xff0c;那就是更好的利用cpu的资源&#xff0c;因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对&#xff0c;因…

使用Maven设置您的应用服务器

在许多情况下&#xff0c;无需先设置应用程序就无法部署应用程序。 在JBoss AS 7.x中&#xff0c;您可能需要配置例如数据库连接。 或者&#xff0c;您必须配置一个安全领域。 也许您还想调整SLSB池…在任何一种情况下&#xff0c;团队中的所有开发人员都必须共享一个共同的或至…

[洛谷P3178][HAOI2015]树上操作

题目大意&#xff1a;有一棵点数为 $N$ 的树&#xff0c;以点 1 为根。然后有 $M$ 个操作。 1. 把 $x$ 的点权增加 $a$ 。 2. 把 $x$ 为根的子树中所有点的点权都增加 $a$ 。 3. 询问 $x$ 到根的路径中所有点的点权和。 题解&#xff1a;树链剖分模板题 卡点&#xff1a;我真的…

实现 通过数据库里一个字段值相等 则把 他合为一条数据

需求&#xff1a; 把红色合为一条数据&#xff0c;绿色合为一条数据 结果&#xff1a; 不多说直接上代码......................................................... // 先查所有数据 const goods await service.goods.findAllGoodsWithParams({where: params,offset: ctx.p…