Spring AOP e JavaConfig nei plugin per Atlassian Jira

In questo lavoro, sviluppiamo un plugin per Atlassian Jira, dove con l'aiuto JavaConfig definire un contenitore con una visibilità zona prototipo, zalogiruem chiama il metodo bean utilizzando l'AOP, e dati in uscita da scomparti esterni (ApplicationProperties, JiraAuthenticationContext e ConstantsManager).

Spina Il codice sorgente può essere preso qui qui .

1. Crea un plugin.

Per fare ciò, apri il terminale e inserisci:

atlas-create-jira-plugin

Alle domande poste nel terminale, è necessario rispondere in questo modo:

Define value for groupId: : ru.matveev.alexey.plugins.spring
Define value for artifactId: : spring-tutorial
Define value for version:  1.0.0-SNAPSHOT: :
Define value for package:  ru.matveev.alexey.plugins.spring: :

groupId: ru.matveev.alexey.plugins.spring
artifactId: spring-tutorial
version: 1.0.0-SNAPSHOT
package: ru.matveev.alexey.plugins.spring
 Y: : Y

2. Apporta le modifiche a pom.xml

È necessario modificare l'ambito di atlassian-spring-scanner-annotation con la compilazione fornita.

<dependency>
    <groupId>com.atlassian.plugin</groupId>
    <artifactId>atlassian-spring-scanner-annotation</artifactId>
    <version>${atlassian.spring.scanner.version}</version>
    <scope>compile</scope>
</dependency>

Rimuovi dipendenza atlassian-spring-scanner-runtime.
Modificare la proprietà atlassian.spring.scanner.version su 2.0.0

Aggiungere le seguenti dipendenze:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.2.5.RELEASE</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.2.5.RELEASE</version>
    <scope>provided</scope>
</dependency>

Aggiungi la seguente riga al plugin maven-jira nel tag delle istruzioni:

<DynamicImport-Package>*</DynamicImport-Package>

Questa linea consentirà al plugin di trovare le classi Spring durante l'esecuzione.

3. Creare un'interfaccia e implementare l'entità HelloWorld.

HelloWorld.java

package ru.matveev.alexey.plugins.spring.api;

public interface HelloWorld {
    String getMessage();
    void setMessage(String value);
}

HelloWorldImpl.java

package ru.matveev.alexey.plugins.spring.impl;

import com.atlassian.jira.config.ConstantsManager;
import com.atlassian.jira.security.JiraAuthenticationContext;
import com.atlassian.sal.api.ApplicationProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.matveev.alexey.plugins.spring.api.HelloWorld;

public class HelloWorldImpl implements HelloWorld {
    private static final Logger LOG = LoggerFactory.getLogger(HelloWorldImpl.class);
    private String message = "Hello World!!!";
    private final ApplicationProperties applicationProperties;
    private final ConstantsManager constantsManager;
    private final JiraAuthenticationContext jiraAuthenticationContext;

    public HelloWorldImpl(ApplicationProperties applicationProperties, JiraAuthenticationContext jiraAuthenticationContext, ConstantsManager constantsManager) {
        this.applicationProperties = applicationProperties;
        this.constantsManager = constantsManager;
        this.jiraAuthenticationContext = jiraAuthenticationContext;
    }

    public String getMessage() {
        LOG.debug("getMessage executed");
        return applicationProperties.getDisplayName() + " logged user: " + jiraAuthenticationContext.getLoggedInUser().getName() + " default priority: " + constantsManager.getDefaultPriority().getName() + " " + this.message;
    }

    public void setMessage(String value) {
        LOG.debug("setMessage executed");
        message = value;
    }
}

La classe accetta tre bean esterni e restituisce i dati da questi bean nel metodo getMessage.

4. Creare una classe per l'importazione di fagioli Jira esportati.

JiraBeansImporter.java

import com.atlassian.jira.config.ConstantsManager;
package ru.matveev.alexey.plugins.spring.impl;

import com.atlassian.jira.security.JiraAuthenticationContext;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import com.atlassian.sal.api.ApplicationProperties;
import javax.inject.Inject;
import javax.inject.Named;

@Named
public class JiraBeansImporter {
@Inject
    public JiraBeansImporter(@ComponentImport ApplicationProperties applicationProperties,
                             @ComponentImport JiraAuthenticationContext jiraAuthenticationContext,
                             @ComponentImport ConstantsManager constantsManager
                           ) {
    }

}

Questa classe è necessaria solo per JavaConfig per vedere i bean esterni da noi richiesti.

5. Creare classi per la registrazione dei dati sui metodi chiamati degli oggetti.

HijackBeforeMethod.java
Questa classe registra le informazioni prima di chiamare il metodo object.

package ru.matveev.alexey.plugins.spring.aop;

import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.MethodBeforeAdvice;

public class HijackBeforeMethod implements MethodBeforeAdvice
{

    private static final Logger LOG = LoggerFactory.getLogger(HijackBeforeMethod.class);
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        LOG.debug("HijackBeforeMethod : method {} in", method.toString());
    }
}

HijackAroundMethod.java
Questa classe registra le informazioni prima e dopo la chiamata al metodo dell'oggetto.

package ru.matveev.alexey.plugins.spring.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;

public class HijackAroundMethod implements MethodInterceptor {

    private static final Logger LOG = LoggerFactory.getLogger(HijackAroundMethod.class);

    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        LOG.debug("HijackAroundMethod : Method name : "
                + methodInvocation.getMethod().getName());
        LOG.debug("HijackAroundMethod : Method arguments : "
                + Arrays.toString(methodInvocation.getArguments()));
        LOG.debug("HijackAroundMethod : Before method hijacked!");
        try {
            Object result = methodInvocation.proceed();
            LOG.debug("HijackAroundMethod : Before after hijacked!");
            return result;
        } catch (IllegalArgumentException e) {
            LOG.debug("HijackAroundMethod : Throw exception hijacked!");
            throw e;
        }
    }
}

6. Creare JavaConfig

package ru.matveev.alexey.plugins.spring.config;

import com.atlassian.jira.config.ConstantsManager;
import com.atlassian.jira.security.JiraAuthenticationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import ru.matveev.alexey.plugins.spring.aop.HijackAroundMethod;
import ru.matveev.alexey.plugins.spring.aop.HijackBeforeMethod;
import com.atlassian.sal.api.ApplicationProperties;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.matveev.alexey.plugins.spring.api.HelloWorld;
import ru.matveev.alexey.plugins.spring.impl.HelloWorldImpl;

@Component
@Configuration
public class Config{
    @Bean(name = "helloWorld")
    @Scope("prototype")
    public HelloWorld helloWorld(ApplicationProperties applicationProperties,
                                 JiraAuthenticationContext jiraAuthenticationContext,
                                 ConstantsManager constantsManager) {
        return new HelloWorldImpl(applicationProperties, jiraAuthenticationContext, constantsManager);
    }

    @Bean(name="hijackBeforeMethodBean")
    public HijackBeforeMethod hijackBeforeMethod() {
        return new HijackBeforeMethod();
    }

    @Bean(name="hijackAroundMethodBean")
    public HijackAroundMethod hijackAroudnMethod() {
        return new HijackAroundMethod();
    }

    @Bean (name = "helloWorldBeforeProxy")
    @Scope("prototype")
    public ProxyFactoryBean proxyBeforeFactoryBean(ApplicationProperties applicationProperties,
                                                   JiraAuthenticationContext jiraAuthenticationContext,
                                                   ConstantsManager constantsManager) {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(helloWorld(applicationProperties,jiraAuthenticationContext,constantsManager));
        proxyFactoryBean.setProxyTargetClass(true);
        proxyFactoryBean.setInterceptorNames("hijackBeforeMethodBean");
        return proxyFactoryBean;
    }

    @Bean (name = "helloWorldAroundProxy")
    @Scope("prototype")
    public ProxyFactoryBean proxyAroundFactoryBean(ApplicationProperties applicationProperties,
                                                   JiraAuthenticationContext jiraAuthenticationContext,
                                                   ConstantsManager constantsManager) {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(helloWorld(applicationProperties,jiraAuthenticationContext,constantsManager));
        proxyFactoryBean.setProxyTargetClass(true);
        proxyFactoryBean.setInterceptorNames("hijackAroundMethodBean");
        return proxyFactoryBean;
    }
}

In JavaConfig, creiamo:

bin helloWorld con lo scopo del prototipo, il che significa che l'istanza bin verrà creata ogni volta che accederai.
i bean hijackBeforeMethodBean e hijackAroundMethodBean che registrano le informazioni prima e dopo le chiamate al metodo degli oggetti.
Bina helloWorldBeforeProxy e helloWorldAroundProxy, che viene inoltrato bin helloWorld e con riferimento ai metodi della helloWorld fagiolo registrate informazioni utilizzando i cassonetti e hijackBeforeMethodBean hijackAroundMethodBean

7. Creare due server.

Servlet verrà utilizzato per testare la nostra applicazione.

Apri il terminale ed esegui:

atlas-create-jira-plugin-module

Quando viene posta una domanda sul tipo di modulo che si sta creando, selezioniamo 21 (Servlet):

Choose a number (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34): 21

Quindi rispondiamo alle domande nel modo seguente:

Enter New Classname MyServlet: : MyServlet1
Enter Package Name ru.matveev.alexey.plugins.spring.servlet: :
Show Advanced Setup? (Y/y/N/n) N: : N
Add Another Plugin Module? (Y/y/N/n) N: : Y
Choose a number (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34): 21
Enter New Classname MyServlet: : MyServlet2
Enter Package Name ru.matveev.alexey.plugins.spring.servlet: :
Show Advanced Setup? (Y/y/N/n) N: : N
Add Another Plugin Module? (Y/y/N/n) N: : N

Di conseguenza, genereremo i file MyServlet1.java e MyServlet2.java. Cambiamo il codice in questi file:
MyServlet1.java
Passiamo al nostro servlet il nostro proxy helloWorldBeforeProxy. Cioè, quando accedi a HelloWorld, le informazioni verranno registrate prima di chiamare i metodi HelloWorld.

package ru.matveev.alexey.plugins.spring.servlet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import ru.matveev.alexey.plugins.spring.api.HelloWorld;
import javax.inject.Inject;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet1 extends HttpServlet{
    private static final Logger log = LoggerFactory.getLogger(MyServlet1.class);
    private final HelloWorld helloWorld;

    @Inject
    public MyServlet1(@Qualifier("helloWorldBeforeProxy") HelloWorld helloWorld) {
        this.helloWorld = helloWorld;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
    {
        log.debug("MyServlet1 called");
        resp.setContentType("text/html");
        String message = "<html><body>" + helloWorld.getMessage() + "</body></html>";
        helloWorld.setMessage("message changed MyServlet");
        resp.getWriter().write(message);
    }
}

MyServlet2.java
Passiamo il nostro proxy helloWorldAroundProxy al servlet. Cioè, quando ci si riferisce a HelloWorld, le informazioni verranno registrate prima e dopo aver chiamato i metodi HelloWorld.

package ru.matveev.alexey.plugins.spring.servlet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import ru.matveev.alexey.plugins.spring.api.HelloWorld;
import javax.inject.Inject;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet2 extends HttpServlet{
    private static final Logger log = LoggerFactory.getLogger(MyServlet2.class);
    private final HelloWorld helloWorld;

    @Inject
    public MyServlet2(@Qualifier("helloWorldAroundProxy") HelloWorld helloWorld) {
        this.helloWorld = helloWorld;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
    {
        log.debug("MyServlet2 called");
        resp.setContentType("text/html");
        String message = "<html><body>" + helloWorld.getMessage() + "</body></html>";
        helloWorld.setMessage("message changed MyServlet");
        resp.getWriter().write(message);
    }
}

8. Controlliamo il risultato.

Dovremmo controllare quanto segue:

Il nostro plugin è stato lanciato.
Le informazioni vengono fornite da bean esterni che stiamo modificando (ApplicationProperties, JiraAuthenticationContext, ConstantsManager)
helloWorld funziona nell'ambito del prototipo.
Vengono registrate informazioni sulle chiamate ai metodi helloWorld.

Apri il terminale e inserisci:

atlas-run

Dopo l'avvio di Jira, aprire Jira nel browser su localhost : 2990 / jira / ed accedere a Jira.

Nessun commento:

Posta un commento