Spring框架附带AOP支持。 实际上,如Spring参考文档中所述 ,
“ Spring的关键组件之一是AOP框架。 尽管Spring IoC容器不依赖于AOP,这意味着您不需要使用AOP,但AOP是对Spring IoC的补充,以提供功能强大的中间件解决方案。 AOP在Spring框架中用于…
- …提供声明性企业服务,尤其是代替EJB声明性服务。 此类服务中最重要的是声明式事务管理。
- …允许用户实现自定义方面,并通过AOP补充其对OOP的使用。 ”
尽管如此,与完整的AOP实现(例如AspectJ)相比, Spring AOP框架还是有某些限制。 人们在使用Spring AOP框架时遇到的最常见问题源于以下事实: Spring AOP是“基于代理的”。 换句话说,当将bean用作依赖项并且应通过特定方面建议其方法时,IoC容器将注入“方面感知” bean代理,而不是bean本身。 为了对用户透明地对代理bean实例执行方法调用,以便在将调用委派给实际的“代理” bean之前和/或之后执行方面逻辑。
此外, Spring AOP框架使用JDK动态代理或CGLIB创建给定目标对象的代理。 第一个只能为接口创建代理,而第二个可以代理具体类,但有一定的限制。 特别是,如Spring参考文档中所述 ,
“ 如果要代理的目标对象实现至少一个接口,则将使用JDK动态代理。 目标类型实现的所有接口都将被代理。 如果目标对象未实现任何接口,则将创建CGLIB代理。 ”
总而言之,在使用Spring AOP框架时,您应该牢记两个重要事项:
- 如果您的“代理” bean实现了至少一个接口,则只能将代理bean强制转换为该接口。 如果尝试将其强制转换为“代理” bean类,则应期望在运行时引发ClassCastException。 尽管如此, Spring AOP框架提供了强制CGLIB代理的选项,但有上述限制(请参阅Spring参考文档的相关章节)
- 方面不适用于术中呼叫。 这意味着代理无法拦截来自相同“代理” bean的另一个方法的方法的调用
我们建议克服以上问题的方法是使用AspectJ编织。 换句话说,将方面逻辑直接注入到目标类中,并消除了代理所有方法的必要性。 有三种方法可以注入AspectJ方面所隐含的指令:
- 编译时间编织–通过AspectJ编译器编译目标源或方面类
- 编译后编织–向已编译的类注入方面指令
- 加载时间编织–在类加载期间向字节码注入方面指令
可以使用上述任何方法。 在本教程中,我们将介绍如何在Spring和Maven中使用AspectJ编译时编织。 我们将实现最小的“问候” Spring服务和相关的“问候” AspectJ方面。 Spring服务方法调用将被AspectJ方面拦截。 AspectJ方面将使用其自己的“问候”消息来丰富Spring服务的“问候”消息。 AspectJ方面的“问候”消息将从Spring容器中注入,只是为了展示如何将Spring依赖项注入到AspectJ方面。
已经为其bean服务实现了方面的Spring用户可以透明地切换到AspectJ ,这意味着由于Spring AOP框架使用AspectJ切入点表达语言的子集而无需编写任何特殊代码,并且@AspectJ Spring方面完全符合AspectJ的编织要求。 。
我们首选的开发环境是Eclipse ,因此,必须先安装具有Maven支持的Eclipse 。 用于Eclipse的Maven插件的安装不在本教程的讨论范围内,因此将不予讨论。 但是,您将需要以下组件:
- 从这里蚀
- 从这里开始 ,Eclipse的Maven插件
在本教程中,我们将使用Eclipse Galileo,“ m2eclipse” Maven Integration for Eclipse插件版本0.10.0,Spring版本3.0.1,aspectjrt版本1.6.7和Aspectj-maven-plugin版本1.3。
让我们开始,
- 创建一个新的Maven项目,转到File? 项目? Maven? Maven项目
- 在向导的“选择项目名称和位置”页面中,确保未选中“创建简单项目(跳过原型选择)”选项,单击“下一步”以继续使用默认值
- 在向导的“选择原型”页面中,在“目录”下拉列表中选择“ Nexus Indexer”,并在刷新原型选择区域后,从“ org.codehaus.mojo”中选择“ webapp-jee5”原型。原型”。 您可以使用“过滤器”文本框来缩小搜索结果范围。 点击“下一步”继续
- 在向导的“输入工件ID”页面中,您可以定义项目的名称和主程序包。 我们将“ Group Id”变量设置为“ com.javacodegeeks”,将“ Artifact Id”变量设置为“ aspectjspring”。 前面提到的选择组成了主项目包“ com.javacodegeeks.aspectjspring”和项目名“ aspectjspring”。 点击“完成”退出向导并创建您的项目
让我们回顾一下有关Maven Web项目结构的一些事情
- / src / main / java文件夹包含应用程序动态内容的源文件
- / src / test / java文件夹包含用于单元测试的所有源文件
- / src / main / webapp文件夹包含用于创建有效的Web应用程序的基本文件,例如“ web.xml”
- / target文件夹包含已编译和打包的可交付成果
- “ pom.xml”是项目对象模型(POM)文件。 包含所有项目相关配置的单个文件。
为了在运行时正确使用Spring ,我们必须向Web应用程序提供所有必需的库。 打开“ pom.xml”的图形编辑器并执行以下更改:
- 在POM编辑器的“概述”页面上的“属性”部分中找到并执行以下更改:
- 创建一个名称为org.springframework.version且值为3.0.1.RELEASE的新属性
- 根据您的Java运行时环境的版本,创建一个名称为maven.compiler.source的新属性,并赋值为value,我们将使用1.6
- 根据您的Java运行时环境的版本创建一个名称为maven.compiler.target的新属性,并将其值设置为value,我们将使用1.6
- 导航到POM编辑器的“ Dependencies”页面,并创建以下依赖关系(您应在该页面的“ Dependency Details”部分的“ GroupId”,“ Artifact Id”和“ Version”字段中进行填充):
- 组ID: org.springframework工件ID: spring-web版本: $ {org.springframework.version}
- 组ID:org.aspectj工件ID:aspectjrt版本:1.6.7
- 导航到POM编辑器的“插件”页面,并创建以下插件(您应在该页面的“插件详细信息”部分的“ GroupId”,“工件ID”和“版本”字段中进行填充):
- 组ID: org.codehaus.mojo工件ID: aspectj-maven-plugin版本: 1.3
- 在POM编辑器的“插件”页面上,选择新创建的插件(从“插件”部分中),并将其绑定到编译执行目标。 为此,请找到“执行”部分并创建一个新的执行。 在“执行详细信息”部分,创建一个新目标并将其命名为“ compile ”
- 新创建的插件需要进行最后的配置更改。 为了使AspectJ编译器正确地编织方面类,我们必须定义所使用的Java运行时环境版本。 我们需要编辑“ pom.xml”文件来执行更改。 选择POM编辑器的“ pom.xml”页面,找到新创建的插件,并如下进行更改:
<plugin><groupId>org.codehaus.mojo</groupId><artifactId>aspectj-maven-plugin</artifactId><version>1.3</version><configuration><source>${maven.compiler.source}</source><target>${maven.compiler.target}</target></configuration><executions><execution><goals><goal>compile</goal></goals></execution></executions> </plugin>
- 最后,如下所示更改“ maven-compiler-plugin”:
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.0.2</version><configuration><source>${maven.compiler.source}</source><target>${maven.compiler.target}</target></configuration> </plugin>
如您所见, Maven以声明方式管理库依赖关系。 创建本地存储库(默认情况下,位于{user_home} /。m2文件夹下),所有必需的库都从公共存储库下载并放置在该库中。 此外,库内的依赖关系会自动解决和处理。
下一步是为Web应用程序提供挂钩,以便在启动时加载Spring上下文。
在/ src / main / webapp / WEB-INF下找到“ web.xml”文件,并添加以下内容:
为了在启动时加载Spring上下文,
<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
现在让我们创建将驱动Spring容器的applicationContext.xml文件。 在/ src / main / webapp / WEB-INF目录下创建文件。 下面是一个示例“ applicationContext.xml”
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"><context:component-scan base-package="com.javacodegeeks.aspectjspring" /><bean class="com.javacodegeeks.aspectjspring.aspects.GreetingAspect" factory-method="aspectOf"><property name="message" value="Hello from Greeting Aspect"/></bean></beans>
这里要注意的事情:
- 将context:component-scan元素的base-package属性更改为项目的基本包,以便扫描Spring组件
- 仅当我们要向它们注入依赖项时,才必须在“ applicationContext.xml”中定义我们的方面
- AspectJ表示术语“方面关联”。 它定义了如何管理方面状态。 支持以下状态关联:
- 每个JVM –构造和使用一个共享的方面实例(默认)
- 每个对象–每个建议对象的方面都有其自己的状态
- 每个控制流–方面在每个特定控制流中都有自己的状态
所有AspectJ方面类都具有“ hasAspect()”和“ aspectOf()”静态方法。 这些方法由AspectJ编译器/加载时间编织器隐式生成。 因此,对于默认的方面状态,可以使用“ aspectOf()”方法来检索一个方面的实例
现在让我们创建“问候” Spring服务和相关的“问候” AspectJ方面。 在主程序包下创建一个名为“服务”的子程序包,并将“ GreetingService”类放在此处。 下面是一个示例“问候”服务:
package com.javacodegeeks.aspectjspring.services;import org.springframework.stereotype.Service;@Service("greetingService") public class GreetingService {public String sayHello() {return "Hello from Greeting Service";}}
在主包下创建一个名为“ aspects”的子包,并将“ GreetingAspect”类放在此处。 下面是一个示例“问候”方面:
package com.javacodegeeks.aspectjspring.aspects;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect;@Aspect public class GreetingAspect {private String message;public void setMessage(String message) {this.message = message;}@Around("execution(* com.javacodegeeks.aspectjspring.services.GreetingService.*(..))")public Object advice(ProceedingJoinPoint pjp) throws Throwable {String serviceGreeting = (String) pjp.proceed();return message + " and " + serviceGreeting;}}
最后,在/ src / main / webapp文件夹下找到项目的主网页“ index.jsp”,并进行如下更改:
<%@ page language="java" import="org.springframework.web.context.WebApplicationContext, org.springframework.web.context.support.WebApplicationContextUtils, com.javacodegeeks.aspectjspring.services.GreetingService"%> <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"><% WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); GreetingService greetingService = (GreetingService) webApplicationContext.getBean("greetingService"); %> <html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>JSP Page</title></head><body><h1>Test service invoked and greets you by saying : <%=greetingService.sayHello()%></h1></body> </html>
这里要注意的事情:
- 页面加载后,我们检索Spring Web应用程序上下文,并查找“问候”服务。 我们要做的就是调用“ sayHello()”方法,从我们的方面和服务中查看合并的问候消息
要构建应用程序,请右键单击您的项目? 运行为? Maven包
要部署Web应用程序,只需将“ .war”文件从“ target”目录复制到Apache – Tomcat “ webapps”文件夹
午餐应用程序将您的浏览器指向以下地址
http:// localhost:8080 / {application_name} /
如果一切顺利,您应该会看到显示以下内容的主网页:
“测试服务被调用并打招呼:“ Greeting Aspect向您问好,Greeting Service向您问好”
您可以从这里下载项目
希望你喜欢
贾斯汀
相关文章 :
- GWT 2 Spring 3 JPA 2 Hibernate 3.5教程
- GWT Spring和Hibernate进入数据网格世界
- Spring3 RESTful Web服务
- GWT 2 Spring 3 JPA 2 Hibernate 3.5教程– Eclipse和Maven 2展示
- 带有Spring和Maven教程的JAX–WS
翻译自: https://www.javacodegeeks.com/2010/07/aspect-oriented-programming-with-spring.html