Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 方面建议其他方面_Java_Spring_Aop_Spring Aop - Fatal编程技术网

Java 方面建议其他方面

Java 方面建议其他方面,java,spring,aop,spring-aop,Java,Spring,Aop,Spring Aop,我目前正在开发两个利用SpringAOP的Spring应用程序。我有一个方面允许简单的性能记录,定义如下: @Aspect final class PerformanceAdvice { private Logger logger = LoggerFactory.getLogger("perfLogger"); public Object log(final ProceedingJoinPoint call) throws Throwable { logger.

我目前正在开发两个利用SpringAOP的Spring应用程序。我有一个方面允许简单的性能记录,定义如下:

@Aspect
final class PerformanceAdvice {
    private Logger logger = LoggerFactory.getLogger("perfLogger");

    public Object log(final ProceedingJoinPoint call) throws Throwable {
        logger.info("Logging statistics.");
    }
}
然后可以使用以下XML通过Spring AOP配置创建此建议:

<bean id="performanceAdvice" class="com.acme.PerformanceAdvice" />

<aop:config>
    <aop:aspect ref="performanceAdvice">
        <aop:around pointcut="execution(* com.acme..*(..))" method="log"/>
    </aop:aspect>
</aop:config>
我现在没有主意了。我是否需要编写成熟的
AspectJ
aspects?如果是这样,它是否可以使用相同的配置(如Spring),引用现有方面并定义新的切入点?这将非常有用,因此我不必为
项目1
重新使用
性能设备
,但仍然在
项目2中引用和使用它

@Service
public class TargetSpringServiceImpl implements TargetSpringService {
    @Override
    public String doSomeComplexThings(String parameter) {
        return "Complex stuff";
    }
}
编辑相关信息: 为了让自己更清楚,我举了下面的例子

我在
项目2中有一项服务

@Service
public class TargetSpringServiceImpl implements TargetSpringService {
    @Override
    public String doSomeComplexThings(String parameter) {
        return "Complex stuff";
    }
}
当调用此方法时,我有一个方面可以进行一些验证

@Aspect
public class ValidationAdvice {
    @Autowired
    ValidationService validationService

    public void validate(JoinPoint jp) throws Throwable {
        //Calls the validationService to validate the parameters
    }
}
执行以下切入点:

<bean id="validationAdvice" class="com.acme.advice.ValidationAdvice" />

<aop:config>
    <aop:aspect ref="validationAdvice">
        <aop:before pointcut="execution(* com.acme.service..*(..))" method="validate"/>
    </aop:aspect>
</aop:config>


我希望在
ValidationAdvice
validate()
方法上调用我的
PerformanceDevice
log()
方法NOT关于
TargetSpringService
类的
doSomeComplexThings()
方法。因为这只是一个额外的切入点。问题在于建议另一个方面的方法。

首先,Spring不使用aspectJ实现AOP,而是使用JDK或cglib动态代理。这里的aspectJ风格只是指语法

<aspectj>
    <aspects>
        <concrete-aspect name="com.example.project2.ConcretePerformanceAdvice" extends="com.example.project1.AbstractPerformanceAdvice">
            <pointcut name="externalPointcut" expression="execution(* com.example.project2.ValidationAdvice.validate(..))"/>
        </concrete-aspect>
    </aspects>    
    <weaver options="-verbose"/>
</aspectj>
Aspectj方面是静态的,在编译或类加载时使用字节码注入

然后,spring只能在其管理的对象上应用代理,因为动态代理是在依赖项注入期间应用的。此外,如果您有两个不同的项目,您必须确保它们共享相同的spring上下文,否则它们将被隔离,并且将方面从1个项目应用到第2个项目的bean将不起作用

是的,您可能需要在这里使用真正的aspectJ方面。出于性能记录的目的,它更合适,因为不会对性能造成影响。

因此(据我所知),您希望在第二个项目中重复使用第一个项目的建议。但另外,您还希望向advice添加进一步的逻辑。这可以通过使用 project-2中的自定义实现。 您可以通过包装其他建议来实现这一点(请参阅):

项目1需要一些小的修改(除了实现
Ordered
之外,您还可以使用
@Order
注释/当然,您也可以插入排序,而不是硬编码):


在您的项目2中创建自定义建议建议实施

public class AdditionalPerformanceAdvice implements Ordered {

   Object log(final ProceedingJoinPoint pjp) throws Throwable {
      ...
      Object result = pjp.proceed(pjp.getArgs());
      ...
      return result;
   }

    @Override
    public int getOrder() {
       return Ordered.HIGHEST_PRECEDENCE;
    }
}
将组件连接在一起:

<!-- component of project 1 -->
<bean id="loggingPerformanceAdvice" class="com.acme.project1.LoggingPerformanceAdvice"/>
<!-- component of project 2 -->
<bean id="additionalPerformanceAdvice" class="com.acme.project2.AdditionalPerformanceAdvice"/>

<aop:config>
   <aop:aspect ref="loggingPerformanceAdvice">
      <aop:around pointcut="execution(* com.acme..*(..))" method="log"/>
   </aop:aspect>
   <aop:aspect ref="additionalPerformanceAdvice">
      <aop:around pointcut="execution(* com.acme..*(..))" method="log"/>
   </aop:aspect>
</aop:config> 


排序为
的Aspect。首先调用最高优先级的

如果我理解您不想对Aspect建议执行操作,我会这样做(使用aspectj可以更改为spring注释):


然后我创建了扩展此方面的其他方面。

我已经找到了解决问题的两种可能的方法。一个实际上是建议方面,另一个围绕问题工作,但实际上更优雅

解决方案1:建议方面 在
AspectJ
中,几乎可以编织任何东西。在中所述的
META-INF/aop.xml
文件的帮助下,我可以引用方面并以以下方式定义新的切入点

对项目1的修改
性能设备
要允许
AspectJ
定义一个新的切入点,建议必须是
abstract
,并且有一个可以连接到的abstract
pointcut
方法

@Aspect
final class PerformanceAdvice extends AbstractPerformanceAdvice {
    @Override
    void externalPointcut(){}
}

@Aspect
public abstract class AbstractPerformanceAdvice {
    private Logger logger = LoggerFactory.getLogger("perfLogger");

    @Pointcut
    abstract void externalPointcut();

    @Around("externalPointcut()")
    public Object log(final ProceedingJoinPoint call) throws Throwable {
        logger.info("Logging statistics.");
    }
}
对项目2的修改
META-INF/aop.xml
aop.xml
文件定义了一个名为
concretePerformanceDevice
的新方面。它还扩展了
AbstractPerformanceDevice
,但定义了一个新的切入点。然后,在
AspectJ
可以定义指向另一个方面的切入点(与Spring AOP不同)

<aspectj>
    <aspects>
        <concrete-aspect name="com.example.project2.ConcretePerformanceAdvice" extends="com.example.project1.AbstractPerformanceAdvice">
            <pointcut name="externalPointcut" expression="execution(* com.example.project2.ValidationAdvice.validate(..))"/>
        </concrete-aspect>
    </aspects>    
    <weaver options="-verbose"/>
</aspectj>
目前,在测试过程中,我通过
surefire插件
进行检测。这需要以下位:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.8</version>
            <configuration>
                <forkMode>once</forkMode>
                <argLine>
                    -javaagent:"${settings.localRepository}/org/springframework/spring-instrument/${org.springframework.version}/spring-instrument-${org.springframework.version}.jar"
                </argLine>
                <useSystemClassloader>true</useSystemClassloader>
            </configuration>
        </plugin>
    </plugins>
</build>
然后在Spring上下文中,可以在
@组件
上定义切入点,而
验证广告
自动连接
@组件

<!-- Scan the package to find the ValidatorDefault component for autowiring -->
<context:component-scan base-package="com.example.project2" />

<bean id="validationAdvice" class="com.example.project2.ValidationAdvice" />
<bean id="performanceAdvice" class="com.example.project1.PerformanceAdvice" />

<aop:config>
    <aop:aspect ref="validationAdvice">
        <aop:before pointcut="execution(* com.acme.service..*.*(..))" method="validate"/>
    </aop:aspect>
    <aop:aspect ref="performanceAdvice">
        <aop:around pointcut="execution(* com.example.project2.ValidatorDefault.validate(..))" method="log"/>
    </aop:aspect>
</aop:config>


你为什么不建议一个方面?你可以只做方面本身的工作。或者,您可以创建另一个方面,建议与第一个方面相同的方法/类/etcone@JEY我想建议另一个方面,以避免代码重复。我可以在每个其他方面编写相同的性能日志逻辑我希望有一些性能日志,但似乎有一个已经存在的方面为我做,而不是复制粘贴逻辑要整洁得多。继承呢?你不需要这个方面来连接多个切入点吗?这就是你需要的吗?@JEY那么
performancedevice
不应该是我的其他方面的超类,因为
performancedevice
应该在方面的方法上“发挥其魔力”。e、 g.与其记录
RandomService
类的
doIt()
方法,不如记录
doIt()时触发的
doBefore()
方法
被调用。我感谢您的详尽回答,如果我需要
PerformanceDevice
的扩展,您将介绍一个很好的实现。不过,我恐怕我说得不够清楚。我不希望扩展
PerformanceDevice
日志记录的功能。我希望在另一个方面的方法上执行
PerformanceDevice
log()
方法。我会
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.8</version>
            <configuration>
                <forkMode>once</forkMode>
                <argLine>
                    -javaagent:"${settings.localRepository}/org/springframework/spring-instrument/${org.springframework.version}/spring-instrument-${org.springframework.version}.jar"
                </argLine>
                <useSystemClassloader>true</useSystemClassloader>
            </configuration>
        </plugin>
    </plugins>
</build>
<context:load-time-weaver/>
@Aspect
public class ValidationAdvice {
    @Autowired
    private ValidatorDefault validatorDefault;

    public void validate(JoinPoint jp) throws Throwable {
        validatorDefault.validate(jp);
    }
}

@Component
public class ValidatorDefault {
    @Autowired
    ValidationService validationService

    public void validate(JoinPoint jp) throws Throwable {
        //Calls the validationService to validate the parameters
    }
}
<!-- Scan the package to find the ValidatorDefault component for autowiring -->
<context:component-scan base-package="com.example.project2" />

<bean id="validationAdvice" class="com.example.project2.ValidationAdvice" />
<bean id="performanceAdvice" class="com.example.project1.PerformanceAdvice" />

<aop:config>
    <aop:aspect ref="validationAdvice">
        <aop:before pointcut="execution(* com.acme.service..*.*(..))" method="validate"/>
    </aop:aspect>
    <aop:aspect ref="performanceAdvice">
        <aop:around pointcut="execution(* com.example.project2.ValidatorDefault.validate(..))" method="log"/>
    </aop:aspect>
</aop:config>