Java的Spring框架下的AOP编程模式示例
作者:goldensun 发布时间:2023-11-02 00:52:25
Spring框架的关键组件是面向方面编程(AOP)框架。面向方面的编程不仅打破程序逻辑分成不同的部分称为所谓的担忧。跨越多个点的应用程序的功能被称为横切关注点和这些横切关注点是从应用程序的业务逻辑概念上区分开来。还有像日志记录,审计,声明性事务,安全性和高速缓存等方面的各种常见的好例子
模块化的OOP中的关键单元是类,而在AOP中模块化的单元则是切面。依赖注入可以帮助你从对方解耦应用程序对象和AOP可以帮助你从他们影响的对象分离横切关注点。 AOP是一样的编程语言如Perl,.NET,Java和其他触发器。
Spring AOP模块提供了 * 拦截的应用程序,例如,执行一个方法时,可以之前或之后执行的方法添加额外的功能。
AOP术语:
在我们开始使用AOP之前,先熟悉AOP的概念和术语。这些条款是不特定于Spring,问题都是有关AOP。
建议的类型
Spring方面可以用5种下面提到的建议:
自定义方面实现
Spring基于XML模式的AOP
需要如下所述导入Spring AOP架构:
<?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 definition & AOP specific configuration -->
</beans>
还需要在以下应用程序CLASSPATH中的AspectJ库。这些库可以在AspectJ的安装'lib'目录可用,可以从互联网上下载它们。
aspectjrt.jar
aspectjweaver.jar
aspectj.jar
声明一个切面
一个方面是使用<aop:aspect>元素中声明,并且支持bean是使用ref属性如下参考:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
这里的“aBean”将配置和依赖注入,就像任何其他的Spring bean,我们已经在前面的章节看到。
声明一个切入点
一个切入点有助于确定与不同要执行的连接点的利息(即方法)。同时与XML架构基础的配置工作,切入点将被定义如下:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
下面的示例定义一个名为'的businessService“切入点将匹配可用的软件包com.yiibai下执行getName()方法在Student类:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.yiibai.Student.getName(..))"/>
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
声明建议
可以声明任意五个建议的使用<aop:{ADVICE NAME}>元素下面给出一个<aop:aspect>内:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<!-- a before advice definition -->
<aop:before pointcut-ref="businessService"
method="doRequiredTask"/>
<!-- an after advice definition -->
<aop:after pointcut-ref="businessService"
method="doRequiredTask"/>
<!-- an after-returning advice definition -->
<!--The doRequiredTask method must have parameter named retVal -->
<aop:after-returning pointcut-ref="businessService"
returning="retVal"
method="doRequiredTask"/>
<!-- an after-throwing advice definition -->
<!--The doRequiredTask method must have parameter named ex -->
<aop:after-throwing pointcut-ref="businessService"
throwing="ex"
method="doRequiredTask"/>
<!-- an around advice definition -->
<aop:around pointcut-ref="businessService"
method="doRequiredTask"/>
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
可以使用相同的doRequiredTask或不同的方法针对不同的建议。这些方法将被定义为纵横模块的一部分。
基于XML模式的AOP例
要理解上述关系到XML模式的AOP提到的概念,让我们写这将实现几个建议的一个例子。
这里是Logging.java文件的内容。这实际上是纵横模块的一个示例,它定义的方法被调用的各个点。
package com.yiibai;
public class Logging {
/**
* This is the method which I would like to execute
* before a selected method execution.
*/
public void beforeAdvice(){
System.out.println("Going to setup student profile.");
}
/**
* This is the method which I would like to execute
* after a selected method execution.
*/
public void afterAdvice(){
System.out.println("Student profile has been setup.");
}
/**
* This is the method which I would like to execute
* when any method returns.
*/
public void afterReturningAdvice(Object retVal){
System.out.println("Returning:" + retVal.toString() );
}
/**
* This is the method which I would like to execute
* if there is an exception raised.
*/
public void AfterThrowingAdvice(IllegalArgumentException ex){
System.out.println("There has been an exception: " + ex.toString());
}
}
以下是Student.java文件的内容:
package com.yiibai;
public class Student {
private Integer age;
private String name;
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
System.out.println("Age : " + age );
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
System.out.println("Name : " + name );
return name;
}
public void printThrowException(){
System.out.println("Exception raised");
throw new IllegalArgumentException();
}
}
以下是MainApp.java文件的内容:
package com.yiibai;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("Beans.xml");
Student student = (Student) context.getBean("student");
student.getName();
student.getAge();
student.printThrowException();
}
}
以下是配置文件beans.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: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 ">
<aop:config>
<aop:aspect id="log" ref="logging">
<aop:pointcut id="selectAll"
expression="execution(* com.yiibai.*.*(..))"/>
<aop:before pointcut-ref="selectAll" method="beforeAdvice"/>
<aop:after pointcut-ref="selectAll" method="afterAdvice"/>
<aop:after-returning pointcut-ref="selectAll"
returning="retVal"
method="afterReturningAdvice"/>
<aop:after-throwing pointcut-ref="selectAll"
throwing="ex"
method="AfterThrowingAdvice"/>
</aop:aspect>
</aop:config>
<!-- Definition for student bean -->
<bean id="student" class="com.yiibai.Student">
<property name="name" value="Zara" />
<property name="age" value="11"/>
</bean>
<!-- Definition for logging aspect -->
<bean id="logging" class="com.yiibai.Logging"/>
</beans>
创建源代码和bean配置文件完成后,让我们运行应用程序。如果一切顺利,这将打印以下信息:
Going to setup student profile.
Name : Zara
Student profile has been setup.
Returning:Zara
Going to setup student profile.
Age : 11
Student profile has been setup.
Returning:11
Going to setup student profile.
Exception raised
Student profile has been setup.
There has been an exception: java.lang.IllegalArgumentException
.....
other exception content
解释一下,上面定义<aop:pointcut>选择所有的包com.yiibai下定义的方法。让我们假设,想有一个特定的方法之前或之后执行意见,可以定义切入点与实际的类和方法的名称取代星号(*)的切入点定义来缩小执行。下面是修改后的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: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 ">
<aop:config>
<aop:aspect id="log" ref="logging">
<aop:pointcut id="selectAll"
expression="execution(* com.yiibai.Student.getName(..))"/>
<aop:before pointcut-ref="selectAll" method="beforeAdvice"/>
<aop:after pointcut-ref="selectAll" method="afterAdvice"/>
</aop:aspect>
</aop:config>
<!-- Definition for student bean -->
<bean id="student" class="com.yiibai.Student">
<property name="name" value="Zara" />
<property name="age" value="11"/>
</bean>
<!-- Definition for logging aspect -->
<bean id="logging" class="com.yiibai.Logging"/>
</beans>
如果执行这些配置更改的示例应用程序,这将打印以下信息:
Going to setup student profile.
Name : Zara
Student profile has been setup.
Age : 11
Exception raised
.....
other exception content
基于@AspectJ的AOP
@ AspectJ是指声明方面的风格注释的使用Java 5注释普通的Java类。对@ AspectJ支持由包括您基于XML Schema的配置文件里面的下列元素启用。
<aop:aspectj-autoproxy/>
您还需要在以下应用程序的类路径中的AspectJ库。这些库可以在AspectJ的安装的'lib'目录,可以从网上下载他们.
aspectjrt.jar
aspectjweaver.jar
aspectj.jar
声明一个切面
方面类是像任何其他普通的bean,并可能有方法和字段,就像任何其他类,但他们将被标注了@Aspect 如下:
package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class AspectModule {
}
他们将在XML中进行配置像任何其他的bean,如下所示:
<bean id="myAspect" class="org.xyz.AspectModule">
<!-- configure properties of aspect here as normal -->
</bean>
声明一个切入点
一个切入点有助于确定与不同意见要执行的连接点的权益(即方法)。同时用@AspectJ的基础配置工作,切入点声明有两个部分:
切入点表达式,决定哪些方法执行我们感兴趣
一个切入点签名的包含名字和任意数量的参数。该方法的实际主体是不相关的,实际上应为空。
下面的示例定义一个名为'businessService“切入点将匹配每个方法的可用包com.xyz.myapp.service下执行中的类:
import org.aspectj.lang.annotation.Pointcut;
@Pointcut("execution(* com.xyz.myapp.service.*.*(..))") // expression
private void businessService() {} // signature
下面的示例定义一个名为'getName'切入点将匹配可用的软件包com.yiibai下执行getName()方法在Student类:
import org.aspectj.lang.annotation.Pointcut;
@Pointcut("execution(* com.yiibai.Student.getName(..))")
private void getname() {}
声明建议
可以声明任何使用 @{ADVICE-NAME} 注释下面给出的五个建议。这假定已经定义了一个切入点签名的方法的businessService():
@Before("businessService()")
public void doBeforeTask(){
...
}
@After("businessService()")
public void doAfterTask(){
...
}
@AfterReturning(pointcut = "businessService()", returning="retVal")
public void doAfterReturnningTask(Object retVal){
// you can intercept retVal here.
...
}
@AfterThrowing(pointcut = "businessService()", throwing="ex")
public void doAfterThrowingTask(Exception ex){
// you can intercept thrown exception here.
...
}
@Around("businessService()")
public void doAroundTask(){
...
}
可以定义内置切入点的任何意见的。下面是一个例子定义内联的切入点之前的建议:
@Before("execution(* com.xyz.myapp.service.*.*(..))")
public doBeforeTask(){
...
}
@AspectJ 基于AOP例子
要理解上述关系到@AspectJ的AOP的基础概念提到,让我们写这将实现几个建议的一个例子。
这里是Logging.java文件的内容。这实际上是方面模块的一个示例,它定义的方法被调用的各个点。
package com.yiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
@Aspect
public class Logging {
/** Following is the definition for a pointcut to select
* all the methods available. So advice will be called
* for all the methods.
*/
@Pointcut("execution(* com.yiibai.*.*(..))")
private void selectAll(){}
/**
* This is the method which I would like to execute
* before a selected method execution.
*/
@Before("selectAll()")
public void beforeAdvice(){
System.out.println("Going to setup student profile.");
}
/**
* This is the method which I would like to execute
* after a selected method execution.
*/
@After("selectAll()")
public void afterAdvice(){
System.out.println("Student profile has been setup.");
}
/**
* This is the method which I would like to execute
* when any method returns.
*/
@AfterReturning(pointcut = "selectAll()", returning="retVal")
public void afterReturningAdvice(Object retVal){
System.out.println("Returning:" + retVal.toString() );
}
/**
* This is the method which I would like to execute
* if there is an exception raised by any method.
*/
@AfterThrowing(pointcut = "selectAll()", throwing = "ex")
public void AfterThrowingAdvice(IllegalArgumentException ex){
System.out.println("There has been an exception: " + ex.toString());
}
}
以下是Student.java文件的内容:
package com.yiibai;
public class Student {
private Integer age;
private String name;
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
System.out.println("Age : " + age );
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
System.out.println("Name : " + name );
return name;
}
public void printThrowException(){
System.out.println("Exception raised");
throw new IllegalArgumentException();
}
}
以下是MainApp.java文件的内容:
package com.yiibai;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("Beans.xml");
Student student = (Student) context.getBean("student");
student.getName();
student.getAge();
student.printThrowException();
}
}
以下是配置文件beans.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: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 ">
<aop:aspectj-autoproxy/>
<!-- Definition for student bean -->
<bean id="student" class="com.yiibai.Student">
<property name="name" value="Zara" />
<property name="age" value="11"/>
</bean>
<!-- Definition for logging aspect -->
<bean id="logging" class="com.yiibai.Logging"/>
</beans>
创建源程序和bean配置文件完成后,让我们运行应用程序。如果一切顺利,这将打印以下信息:
Going to setup student profile.
Name : Zara
Student profile has been setup.
Returning:Zara
Going to setup student profile.
Age : 11
Student profile has been setup.
Returning:11
Going to setup student profile.
Exception raised
Student profile has been setup.
There has been an exception: java.lang.IllegalArgumentException
.....
other exception content
猜你喜欢
- 前言:本文主要讲解以c语言编写猜数字游戏,目的是介绍C语言中的循环和分支的具体用法。一:猜数字游戏基本介绍&对程序预期.猜数字游戏,
- 采用继承Thead类实现多线程:优势:编写简单,如果需要访问当前线程,只需使用this即可,无需使用Thead.currentThread(
- 本文实例为大家分享了Android绝对布局AbsoluteLayout的具体代码,供大家参考,具体内容如下1>AbsoluteLayo
- 一、项目概述之前有不少粉丝私信我说,能不能用Android原生的语言开发一款在手机上运行的游戏呢?说实话,使用java语言直接开发游戏这个需
- 本文主要介绍我为桌面和 Web 设计的一个超级秘密 Flutter 项目使用了画布和可拖动节点界面。本教程将展示我如何使用堆栈来使用小部件完
- spring in action第三版读书笔记spring3.0引入了spring expression language(spel)语言,
- Servlet 实现文件上传所谓文件上传就是将本地的文件发送到服务器中保存。例如我们向百度网盘中上传本地的资源或者我们将写好的博客上传到服务
- Spring JPA 增加字段执行异常用Spring jpa Entity里面增加了几个字段,但启动报错,提示column Unable t
- SpringBoot集成Mybatis时mybatis.mapper-locations和@MapperScan的作用1、mybatis.m
- 本文实例为大家分享了OpenCV实现人脸识别程序的具体代码,供大家参考,具体内容如下//Haar特征检测,人脸识别算法,是用xml作为训练后
- 题目描述Java创建线程的几种方式Java使用Thread类代表线程,所有线程对象都必须是Thread类或者其子类的实例。Java可以用以下
- 引语:工作中有时候需要在普通的对象中去调用spring管理的对象,但是在普通的java对象直接使用@Autowired或者@Resource
- 1: .net framework 由两个部分组成:CLR 和 FCL。2:在CLR中,所有错误都是通过异常来报告的。3:智能感知功能主要是
- 原理是使用LinkedHashMap来实现,当缓存超过大小时,将会删除最老的一个元组。实现代码如下所示import java.util.Li
- 错误处理到目前为止,我们都没怎么介绍onComplete()和onError()函数。这两个函数用来通知订阅者,被观察的对象将停止发送数据以
- 在 Java 语言中,运算符有算数运算符、关系运算符、逻辑运算符、赋值运算符、字符串连接运算符、条件运算符。算数运算符算数运算符是我们最常用
- 概述: 当希望能直接在数据库语言中只检索符合条件的记录,不需要再通过程序对其做处理时,SQL语句分页
- 封面图下个季度的目标是把前端监控相关的内容梳理出来,梳理出来之后可能会在公司内部做个分享~Flutter应用程序既括代码也包括一些其他的资产
- 本文介绍Android中的5种数据存储方式。数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是
- C# 关于Invoke首先说下,invoke和begininvoke的使用有两种情况:control中的invoke、begininvoke