使用Spring AspectJ和Maven进行面向方面的编程

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框架时,您应该牢记两个重要事项:

  1. 如果您的“代理” bean实现了至少一个接口,则只能将代理bean强制转换为该接口。 如果尝试将其强制转换为“代理” bean类,则应期望在运行时引发ClassCastException。 尽管如此, Spring AOP框架提供了强制CGLIB代理的选项,但有上述限制(请参阅Spring参考文档的相关章节)
  2. 方面不适用于术中呼叫。 这意味着代理无法拦截来自相同“代理” bean的另一个方法的方法的调用

我们建议克服以上问题的方法是使用AspectJ编织。 换句话说,将方面逻辑直接注入到目标类中,并消除了代理所有方法的必要性。 有三种方法可以注入AspectJ方面所隐含的指令:

  1. 编译时间编织–通过AspectJ编译器编译目标源或方面类
  2. 编译后编织–向已编译的类注入方面指令
  3. 加载时间编织–在类加载期间向字节码注入方面指令

可以使用上述任何方法。 在本教程中,我们将介绍如何在SpringMaven中使用AspectJ编译时编织。 我们将实现最小的“问候” Spring服务和相关的“问候” AspectJ方面。 Spring服务方法调用将被AspectJ方面拦截。 AspectJ方面将使用其自己的“问候”消息来丰富Spring服务的“问候”消息。 AspectJ方面的“问候”消息将从Spring容器中注入,只是为了展示如何将Spring依赖项注入到AspectJ方面。

已经为其bean服务实现了方面的Spring用户可以透明地切换到AspectJ ,这意味着由于Spring AOP框架使用AspectJ切入点表达语言的子集而无需编写任何特殊代码,并且@AspectJ Spring方面完全符合AspectJ的编织要求。 。

我们首选的开发环境是Eclipse ,因此,必须先安装具有Maven支持的Eclipse 。 用于EclipseMaven插件的安装不在本教程的讨论范围内,因此将不予讨论。 但是,您将需要以下组件:

  1. 这里
  2. 这里开始 ,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。

让我们开始,

  1. 创建一个新的Maven项目,转到File? 项目? Maven? Maven项目
  2. 在向导的“选择项目名称和位置”页面中,确保未选中“创建简单项目(跳过原型选择)”选项,单击“下一步”以继续使用默认值
  3. 在向导的“选择原型”页面中,在“目录”下拉列表中选择“ Nexus Indexer”,并在刷新原型选择区域后,从“ org.codehaus.mojo”中选择“ webapp-jee5”原型。原型”。 您可以使用“过滤器”文本框来缩小搜索结果范围。 点击“下一步”继续
  4. 在向导的“输入工件ID”页面中,您可以定义项目的名称和主程序包。 我们将“ Group Id”变量设置为“ com.javacodegeeks”,将“ Artifact Id”变量设置为“ aspectjspring”。 前面提到的选择组成了主项目包“ com.javacodegeeks.aspectjspring”和项目名“ aspectjspring”。 点击“完成”退出向导并创建您的项目

让我们回顾一下有关Maven Web项目结构的一些事情

  1. / src / main / java文件夹包含应用程序动态内容的源文件
  2. / src / test / java文件夹包含用于单元测试的所有源文件
  3. / src / main / webapp文件夹包含用于创建有效的Web应用程序的基本文件,例如“ web.xml”
  4. / target文件夹包含已编译和打包的可交付成果
  5. “ pom.xml”是项目对象模型(POM)文件。 包含所有项目相关配置的单个文件。

为了在运行时正确使用Spring ,我们必须向Web应用程序提供所有必需的库。 打开“ pom.xml”的图形编辑器并执行以下更改:

  1. 在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
            1. 导航到POM编辑器的“插件”页面,并创建以下插件(您应在该页面的“插件详细信息”部分的“ GroupId”,“工件ID”和“版本”字段中进行填充):
              • 组ID: org.codehaus.mojo工件ID: aspectj-maven-plugin版本: 1.3
              1. 在POM编辑器的“插件”页面上,选择新创建的插件(从“插件”部分中),并将其绑定到编译执行目标。 为此,请找到“执行”部分并创建一个新的执行。 在“执行详细信息”部分,创建一个新目标并将其命名为“ compile
              2. 新创建的插件需要进行最后的配置更改。 为了使AspectJ编译器正确地编织方面类,我们必须定义所使用的Java运行时环境版本。 我们需要编辑“ pom.xml”文件来执行更改。 选择POM编辑器的“ pom.xml”页面,找到新创建的插件,并如下进行更改:
              3. <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>
              4. 最后,如下所示更改“ maven-compiler-plugin”:
              5. <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.xsd
                   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
                   http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
                   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                   http://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>

                这里要注意的事情:

                1. 将context:component-scan元素的base-package属性更改为项目的基本包,以便扫描Spring组件
                2. 仅当我们要向它们注入依赖项时,才必须在“ applicationContext.xml”中定义我们的方面
                3. 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>

                这里要注意的事情:

                1. 页面加载后,我们检索Spring Web应用程序上下文,并查找“问候”服务。 我们要做的就是调用“ sayHello()”方法,从我们的方面和服务中查看合并的问候消息

                要构建应用程序,请右键单击您的项目? 运行为? Maven包

                要部署Web应用程序,只需将“ .war”文件从“ target”目录复制到Apache – Tomcat “ webapps”文件夹

                午餐应用程序将您的浏览器指向以下地址

                http:// localhost:8080 / {application_name} /

                如果一切顺利,您应该会看到显示以下内容的主网页:

                “测试服务被调用并打招呼:“ Greeting Aspect向您问好,Greeting Service向您问好”

                您可以从这里下载项目

                希望你喜欢

                贾斯汀

                相关文章 :

                翻译自: https://www.javacodegeeks.com/2010/07/aspect-oriented-programming-with-spring.html

              评论
              添加红包

              请填写红包祝福语或标题

              红包个数最小为10个

              红包金额最低5元

              当前余额3.43前往充值 >
              需支付:10.00
              成就一亿技术人!
              领取后你会自动成为博主和红包主的粉丝 规则
              hope_wisdom
              发出的红包
              实付
              使用余额支付
              点击重新获取
              扫码支付
              钱包余额 0

              抵扣说明:

              1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
              2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

              余额充值