添加 apache kafka 依赖项后 Jira 插件失败

Jira plugin fails after adding apache kafka dependancy

我正在尝试创建一个 JIRA 插件,以便在创建问题时将其发布到 Kafka 集群。 sample listener code 工作正常。但是,当我为 Kafka 添加 Maven 依赖项时,插件无法加载并出现以下错误。

org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from URL [bundle://219.0:0/META-INF/spring/plugin-context.xml]; nested exception is org.springframework.beans.FatalBeanException: Class [com.atlassian.plugin.spring.scanner.extension.AtlassianScannerNamespaceHandler] for namespace [http://www.atlassian.com/schema/atlassian-scanner] does not implement the [org.springframework.beans.factory.xml.NamespaceHandler] interface
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:414)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:187)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:223)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:194)
    at org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext.loadBeanDefinitions(OsgiBundleXmlApplicationContext.java:171)
    at org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext.loadBeanDefinitions(OsgiBundleXmlApplicationContext.java:141)
    at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:133)
    at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:619)
    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.access0(AbstractDelegatedExecutionApplicationContext.java:57)
    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.run(AbstractDelegatedExecutionApplicationContext.java:239)
    at org.eclipse.gemini.blueprint.util.internal.PrivilegedUtils.executeWithCustomTCCL(PrivilegedUtils.java:85)
    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.startRefresh(AbstractDelegatedExecutionApplicationContext.java:217)
    at org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor.stageOne(DependencyWaiterApplicationContextExecutor.java:224)
    at org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor.refresh(DependencyWaiterApplicationContextExecutor.java:177)
    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.refresh(AbstractDelegatedExecutionApplicationContext.java:154)
    at org.eclipse.gemini.blueprint.extender.internal.activator.LifecycleManager.run(LifecycleManager.java:213)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.FatalBeanException: Class [com.atlassian.plugin.spring.scanner.extension.AtlassianScannerNamespaceHandler] for namespace [http://www.atlassian.com/schema/atlassian-scanner] does not implement the [org.springframework.beans.factory.xml.NamespaceHandler] interface
    at org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolve(DefaultNamespaceHandlerResolver.java:132)
    at org.eclipse.gemini.blueprint.context.support.DelegatedNamespaceHandlerResolver.resolve(DelegatedNamespaceHandlerResolver.java:55)
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1361)
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1352)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:178)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:98)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:508)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:392)
    ... 20 more
2020-09-04 18:06:54,517+0530 ThreadPoolAsyncTaskExecutor::Thread 26 ERROR yogeshpitale 1031x426x4 3reejl 127.0.0.1 /rest/plugins/1.0/installed-marketplace [o.e.g.b.e.internal.support.ExtenderConfiguration] Application context refresh failed (NonValidatingOsgiBundleXmlApplicationContext(bundle=com.vz.jira.defects-plugin, config=osgibundle:/META-INF/spring/*.xml))
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from URL [bundle://219.0:0/META-INF/spring/plugin-context.xml]; nested exception is org.springframework.beans.FatalBeanException: Class [com.atlassian.plugin.spring.scanner.extension.AtlassianScannerNamespaceHandler] for namespace [http://www.atlassian.com/schema/atlassian-scanner] does not implement the [org.springframework.beans.factory.xml.NamespaceHandler] interface
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:414)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:187)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:223)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:194)
    at org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext.loadBeanDefinitions(OsgiBundleXmlApplicationContext.java:171)
    at org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext.loadBeanDefinitions(OsgiBundleXmlApplicationContext.java:141)
    at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:133)
    at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:619)
    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.access0(AbstractDelegatedExecutionApplicationContext.java:57)
    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.run(AbstractDelegatedExecutionApplicationContext.java:239)
    at org.eclipse.gemini.blueprint.util.internal.PrivilegedUtils.executeWithCustomTCCL(PrivilegedUtils.java:85)
    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.startRefresh(AbstractDelegatedExecutionApplicationContext.java:217)
    at org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor.stageOne(DependencyWaiterApplicationContextExecutor.java:224)
    at org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor.refresh(DependencyWaiterApplicationContextExecutor.java:177)
    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.refresh(AbstractDelegatedExecutionApplicationContext.java:154)
    at org.eclipse.gemini.blueprint.extender.internal.activator.LifecycleManager.run(LifecycleManager.java:213)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.FatalBeanException: Class [com.atlassian.plugin.spring.scanner.extension.AtlassianScannerNamespaceHandler] for namespace [http://www.atlassian.com/schema/atlassian-scanner] does not implement the [org.springframework.beans.factory.xml.NamespaceHandler] interface
    at org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolve(DefaultNamespaceHandlerResolver.java:132)
    at org.eclipse.gemini.blueprint.context.support.DelegatedNamespaceHandlerResolver.resolve(DelegatedNamespaceHandlerResolver.java:55)
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1361)
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1352)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:178)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:98)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:508)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:392)
    ... 20 more
2020-09-04 18:06:54,517+0530 ThreadPoolAsyncTaskExecutor::Thread 26 ERROR yogeshpitale 1031x426x4 3reejl 127.0.0.1 /rest/plugins/1.0/installed-marketplace [o.e.g.b.e.i.dependencies.startup.DependencyWaiterApplicationContextExecutor] Unable to create application context for [com.vz.jira.defects-plugin], unsatisfied dependencies: none
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from URL [bundle://219.0:0/META-INF/spring/plugin-context.xml]; nested exception is org.springframework.beans.FatalBeanException: Class [com.atlassian.plugin.spring.scanner.extension.AtlassianScannerNamespaceHandler] for namespace [http://www.atlassian.com/schema/atlassian-scanner] does not implement the [org.springframework.beans.factory.xml.NamespaceHandler] interface
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:414)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:187)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:223)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:194)
    at org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext.loadBeanDefinitions(OsgiBundleXmlApplicationContext.java:171)
    at org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext.loadBeanDefinitions(OsgiBundleXmlApplicationContext.java:141)
    at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:133)
    at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:619)
    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.access0(AbstractDelegatedExecutionApplicationContext.java:57)
    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.run(AbstractDelegatedExecutionApplicationContext.java:239)
    at org.eclipse.gemini.blueprint.util.internal.PrivilegedUtils.executeWithCustomTCCL(PrivilegedUtils.java:85)
    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.startRefresh(AbstractDelegatedExecutionApplicationContext.java:217)
    at org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor.stageOne(DependencyWaiterApplicationContextExecutor.java:224)
    at org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor.refresh(DependencyWaiterApplicationContextExecutor.java:177)
    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.refresh(AbstractDelegatedExecutionApplicationContext.java:154)
    at org.eclipse.gemini.blueprint.extender.internal.activator.LifecycleManager.run(LifecycleManager.java:213)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.FatalBeanException: Class [com.atlassian.plugin.spring.scanner.extension.AtlassianScannerNamespaceHandler] for namespace [http://www.atlassian.com/schema/atlassian-scanner] does not implement the [org.springframework.beans.factory.xml.NamespaceHandler] interface
    at org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolve(DefaultNamespaceHandlerResolver.java:132)
    at org.eclipse.gemini.blueprint.context.support.DelegatedNamespaceHandlerResolver.resolve(DelegatedNamespaceHandlerResolver.java:55)
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1361)
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1352)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:178)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:98)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:508)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:392)
    ... 20 more

下面是我的pom.xml

 <?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.vz.jira</groupId>
    <artifactId>jira-defects-plugin</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <organization>
        <name>Example Company</name>
        <url>http://www.example.com/</url>
    </organization>

    <name>jira-defects-plugin</name>
    <description>This is the com.vz.jira:jira-defects-plugin plugin for Atlassian JIRA.</description>
    <packaging>atlassian-plugin</packaging>

    <dependencies>
        <dependency>
            <groupId>com.atlassian.jira</groupId>
            <artifactId>jira-api</artifactId>
            <version>${jira.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- Add dependency on jira-core if you want access to JIRA implementation 
            classes as well as the sanctioned API. -->
        <!-- This is not normally recommended, but may be required eg when migrating 
            a plugin originally developed against JIRA 4.x -->
        <!-- <dependency> <groupId>com.atlassian.jira</groupId> <artifactId>jira-core</artifactId> 
            <version>${jira.version}</version> <scope>provided</scope> </dependency> -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>

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

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

        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
            <scope>provided</scope>
        </dependency>

        <!-- WIRED TEST RUNNER DEPENDENCIES -->
        <dependency>
            <groupId>com.atlassian.plugins</groupId>
            <artifactId>atlassian-plugins-osgi-testrunner</artifactId>
            <version>${plugin.testrunner.version}</version>
            <scope>test</scope>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.10.RELEASE</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-streams -->
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-streams</artifactId>
            <version>2.0.1</version>
            <!-- <scope>provided</scope> -->
        </dependency>
    
        <!-- https://mvnrepository.com/artifact/org.springframework.kafka/spring-kafka -->
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
            <!-- <version>2.5.4.RELEASE</version> -->
            <!-- <scope>provided</scope> -->
            <version>2.0.1.RELEASE</version>
        </dependency>


        <!-- Uncomment to use TestKit in your project. Details at https://bitbucket.org/atlassian/jira-testkit -->
        <!-- You can read more about TestKit at https://developer.atlassian.com/display/JIRADEV/Plugin+Tutorial+-+Smarter+integration+testing+with+TestKit -->
        <!-- <dependency> <groupId>com.atlassian.jira.tests</groupId> <artifactId>jira-testkit-client</artifactId> 
            <version>${testkit.version}</version> <scope>test</scope> </dependency> -->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>com.atlassian.maven.plugins</groupId>
                <artifactId>jira-maven-plugin</artifactId>
                <version>${amps.version}</version>
                <extensions>true</extensions>
                <configuration>
                    <extractDependencies>true</extractDependencies>
                    <productVersion>${jira.version}</productVersion>
                    <productDataVersion>${jira.version}</productDataVersion>
                    <log4jProperties>src/aps/log4j.properties</log4jProperties>
                    <!-- Uncomment to install TestKit backdoor in JIRA. -->
                    <!-- <pluginArtifacts> <pluginArtifact> <groupId>com.atlassian.jira.tests</groupId> 
                        <artifactId>jira-testkit-plugin</artifactId> <version>${testkit.version}</version> 
                        </pluginArtifact> </pluginArtifacts> -->
                    <enableQuickReload>true</enableQuickReload>

                    <!-- See here for an explanation of default instructions: -->
                    <!-- https://developer.atlassian.com/docs/advanced-topics/configuration-of-instructions-in-atlassian-plugins -->
                    <instructions>
                        <Atlassian-Plugin-Key>${atlassian.plugin.key}</Atlassian-Plugin-Key>

                        <!-- Add package to export here -->
                        <Export-Package>
                            com.vz.jira.api,
                        </Export-Package>

                        <!-- Add package import here -->
                        <Import-Package>
                            org.springframework.osgi.*;resolution:="optional",
                            org.eclipse.gemini.blueprint.*;resolution:="optional",
                            org.springframework.kafka.*;resolution:="optional",
                            org.apache.kafka.*;resolution:="optional",
                            org.apache.kafka.clients.*;resolution:="optional",
                            org.apache.kafka.common.*;resolution:="optional",
                            *;version="0";resolution:=optional
                        </Import-Package>

                        <!-- Ensure plugin is spring powered -->
                        <Spring-Context>*</Spring-Context>
                    </instructions>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependency</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.outputDirectory}/META-INF/lib</outputDirectory>
                            <includeArtifactIds>spring-jdbc,spring-tx</includeArtifactIds>
                            <stripVersion>false</stripVersion>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>com.atlassian.plugin</groupId>
                <artifactId>atlassian-spring-scanner-maven-plugin</artifactId>
                <version>${atlassian.spring.scanner.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>atlassian-spring-scanner</goal>
                        </goals>
                        <phase>process-classes</phase>
                    </execution>
                </executions>
                <configuration>
                    <scannedDependencies>
                        <dependency>
                            <groupId>com.atlassian.plugin</groupId>
                            <artifactId>atlassian-spring-scanner-external-jar</artifactId>
                        </dependency>
                    </scannedDependencies>
                    <verbose>false</verbose>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <properties>
        <jira.version>7.13.0</jira.version>
        <amps.version>8.0.2</amps.version>
        <plugin.testrunner.version>2.0.1</plugin.testrunner.version>
        <atlassian.spring.scanner.version>1.2.13</atlassian.spring.scanner.version>
        <!-- This property ensures consistency between the key in atlassian-plugin.xml 
            and the OSGi bundle's key. -->
        <atlassian.plugin.key>${project.groupId}.${project.artifactId}</atlassian.plugin.key>
        <!-- TestKit version 6.x for JIRA 6.x -->
        <testkit.version>6.3.11</testkit.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

</project>

下面是我的 Java class.

package com.vz.jira.listeners;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;

import com.atlassian.event.api.EventListener;
import com.atlassian.event.api.EventPublisher;
import com.atlassian.jira.event.issue.IssueEvent;
import com.atlassian.jira.event.type.EventType;
import com.atlassian.jira.issue.Issue;
import com.atlassian.plugin.spring.scanner.annotation.imports.JiraImport;

@Component
public class IssueCreatedResolvedListener implements InitializingBean, DisposableBean {

    private static final Logger log = LoggerFactory.getLogger(IssueCreatedResolvedListener.class);
    
    @JiraImport
    private final EventPublisher eventPublisher;
    
    @Autowired
    private KafkaTemplate<Long, String> template;
    
    @Autowired
    public IssueCreatedResolvedListener(@JiraImport EventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }
    
    @EventListener
    public void onIssueEvent(IssueEvent issueEvent) {
       Long eventTypeId = issueEvent.getEventTypeId();
       Issue issue = issueEvent.getIssue();
       System.out.println("Got Issue with ID:"+issue.getId());
       try{
           System.out.println("Sending message to queue");
           this.template.send("issue",issue.getId(),issue.toString());
           System.out.println("Message sent to queue");
       }catch(Exception e){
           e.printStackTrace();
       }
       if (eventTypeId.equals(EventType.ISSUE_CREATED_ID)) {
          log.info("Issue {} has been created at {}.", issue.getKey(), issue.getCreated());
       } else if (eventTypeId.equals(EventType.ISSUE_RESOLVED_ID)) {
          log.info("Issue {} has been resolved at {}.", issue.getKey(), issue.getResolutionDate());
       } else if (eventTypeId.equals(EventType.ISSUE_CLOSED_ID)) {
          log.info("Issue {} has been closed at {}.", issue.getKey(), issue.getUpdated());
       }
    }

    @Override
    public void destroy() throws Exception {
        log.info("Disabling plugin");
        eventPublisher.unregister(this);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("Enabling plugin");
        eventPublisher.register(this);      
    }
}

我尝试通过 OSGI 浏览器调试(参见附图)。 对于某些导入的包,缺少“提供者”。我想知道这是否导致插件失败但无法理解如何解决它。

终于解决了这个问题。这是我所做的。

  1. 删除了 kafka-streams 并非真正需要的依赖项。
  2. 为所有依赖项保留 <scope>provided</scope>
  3. 因为 JAR 需要在运行时可用。我将它们添加到插件>执行>配置>includeArtifactIds,以便将 JAR 导出到运行时环境
  4. 这很重要。 我试验了不同版本的 Kafka。由于我使用的 JIRA 版本是 8.5.4(几年前发布),我发现在同一时间段之前发布的其他 JAR 版本 during/just 并使用了这些版本。
  5. 我遇到了一些缺失的 classes 的运行时问题。我在 plugin>execution>configuration>includeArtifactIds
  6. 中添加了这些工件 ID

现在我的最终 POM 如下所示。

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.vz.jira</groupId>
    <artifactId>jira-defects-plugin</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <organization>
        <name>Example Company</name>
        <url>http://www.example.com/</url>
    </organization>

    <name>jira-defects-plugin</name>
    <description>This is the com.vz.jira:jira-defects-plugin plugin for Atlassian JIRA.</description>
    <packaging>atlassian-plugin</packaging>

    <dependencies>
        <dependency>
            <groupId>com.atlassian.jira</groupId>
            <artifactId>jira-api</artifactId>
            <version>${jira.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- Add dependency on jira-core if you want access to JIRA implementation 
            classes as well as the sanctioned API. -->
        <!-- This is not normally recommended, but may be required eg when migrating 
            a plugin originally developed against JIRA 4.x -->
        <!-- <dependency> <groupId>com.atlassian.jira</groupId> <artifactId>jira-core</artifactId> 
            <version>${jira.version}</version> <scope>provided</scope> </dependency> -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>

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

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

        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
            <scope>provided</scope>
        </dependency>

        <!-- WIRED TEST RUNNER DEPENDENCIES -->
        <dependency>
            <groupId>com.atlassian.plugins</groupId>
            <artifactId>atlassian-plugins-osgi-testrunner</artifactId>
            <version>${plugin.testrunner.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.7.RELEASE</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
            <version>2.2.8.RELEASE</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>2.2.1</version>
            <scope>provided</scope>
        </dependency>

        <!-- Uncomment to use TestKit in your project. Details at https://bitbucket.org/atlassian/jira-testkit -->
        <!-- You can read more about TestKit at https://developer.atlassian.com/display/JIRADEV/Plugin+Tutorial+-+Smarter+integration+testing+with+TestKit -->
        <!-- <dependency> <groupId>com.atlassian.jira.tests</groupId> <artifactId>jira-testkit-client</artifactId> 
            <version>${testkit.version}</version> <scope>test</scope> </dependency> -->
        <!-- <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> 
            <version>2.10.0</version> <scope>provided</scope> </dependency> <dependency> 
            <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> 
            <version>2.10.0</version> <scope>provided</scope> </dependency> <dependency> 
            <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> 
            <version>5.2.0.RELEASE</version> <scope>provided</scope> </dependency> -->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>com.atlassian.maven.plugins</groupId>
                <artifactId>jira-maven-plugin</artifactId>
                <version>${amps.version}</version>
                <extensions>true</extensions>
                <configuration>
                    <extractDependencies>true</extractDependencies>
                    <productVersion>${jira.version}</productVersion>
                    <productDataVersion>${jira.version}</productDataVersion>
                    <log4jProperties>src/aps/log4j.properties</log4jProperties>
                    <!-- Uncomment to install TestKit backdoor in JIRA. -->
                    <!-- <pluginArtifacts> <pluginArtifact> <groupId>com.atlassian.jira.tests</groupId> 
                        <artifactId>jira-testkit-plugin</artifactId> <version>${testkit.version}</version> 
                        </pluginArtifact> </pluginArtifacts> -->
                    <enableQuickReload>true</enableQuickReload>

                    <!-- See here for an explanation of default instructions: -->
                    <!-- https://developer.atlassian.com/docs/advanced-topics/configuration-of-instructions-in-atlassian-plugins -->
                    <instructions>
                        <Atlassian-Plugin-Key>${atlassian.plugin.key}</Atlassian-Plugin-Key>

                        <!-- Add package to export here -->
                        <Export-Package>
                            com.vz.jira.api,
                        </Export-Package>

                        <!-- Add package import here -->
                        <Import-Package>
                            <!-- org.springframework.osgi.*;resolution:="optional", org.eclipse.gemini.blueprint.*;resolution:="optional", 
                                org.springframework.kafka.*;resolution:="optional", org.apache.kafka.*;resolution:="optional", 
                                org.apache.kafka.clients.*;resolution:="optional", org.apache.kafka.common.*;resolution:="optional", -->
                            *;version="0";resolution:=optional
                        </Import-Package>
                        <DynamicImport-Package>*</DynamicImport-Package>
                        <!-- Ensure plugin is spring powered -->
                        <Spring-Context>*</Spring-Context>
                    </instructions>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependency</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.outputDirectory}/META-INF/lib</outputDirectory>
                            <includeArtifactIds>spring-kafka,kafka-clients,spring-context,spring-messaging</includeArtifactIds>
                            <stripVersion>false</stripVersion>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>com.atlassian.plugin</groupId>
                <artifactId>atlassian-spring-scanner-maven-plugin</artifactId>
                <version>${atlassian.spring.scanner.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>atlassian-spring-scanner</goal>
                        </goals>
                        <phase>process-classes</phase>
                    </execution>
                </executions>
                <configuration>
                    <scannedDependencies>
                        <dependency>
                            <groupId>com.atlassian.plugin</groupId>
                            <artifactId>atlassian-spring-scanner-external-jar</artifactId>
                        </dependency>
                    </scannedDependencies>
                    <verbose>false</verbose>
                </configuration>
            </plugin>
        </plugins>
    </build>
<properties>
    <jira.version>7.13.0</jira.version>
    <amps.version>8.0.2</amps.version>
    <plugin.testrunner.version>2.0.1</plugin.testrunner.version>
    <atlassian.spring.scanner.version>1.2.13</atlassian.spring.scanner.version>
    <!-- This property ensures consistency between the key in atlassian-plugin.xml 
        and the OSGi bundle's key. -->
    <atlassian.plugin.key>${project.groupId}.${project.artifactId}</atlassian.plugin.key>
    <!-- TestKit version 6.x for JIRA 6.x -->
    <testkit.version>6.3.11</testkit.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

Kafka 模板相关设置在另一个 class 文件中完成,如下所示。

@Scanned
public class KafkaConfig {

    @Bean
    public ProducerFactory<Long, String> producerFactory() {
        return new DefaultKafkaProducerFactory<>(producerConfigs());
    }

    @Bean
    public Map<String, Object> producerConfigs() {
        System.out.println("Intiailizing the config");
        Map<String, Object> props = new HashMap<>();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092,localhost:9093");

        props.put(ProducerConfig.RETRIES_CONFIG, 1);
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, LongSerializer.class);
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
        props.put(ProducerConfig.LINGER_MS_CONFIG, 1);
        props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 33554432);
        /*props.put(ProducerConfig.ACKS_CONFIG, "all");
        props.put(ProducerConfig.RETRIES_CONFIG, 10);*/
        return props;
    }

    @Bean
    public KafkaTemplate<Long, String> kafkaTemplate() {
        return new KafkaTemplate<Long, String>(producerFactory());
    }
    
}

即使在添加 @Configuration 注释之后,我也无法通过 Spring 配置和自动装配 KafkaTemplate。因此使用下面的代码手动实例化它(虽然这不是一个好方法!)

private KafkaTemplate<Long, String> template= new KafkaConfig().kafkaTemplate();

并使用以下代码将主题发送到 Kafka。

package com.vz.jira.listeners;


import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;

import com.atlassian.event.api.EventListener;
import com.atlassian.event.api.EventPublisher;
import com.atlassian.jira.event.issue.IssueEvent;
import com.atlassian.jira.issue.Issue;
import com.atlassian.plugin.spring.scanner.annotation.component.Scanned;
import com.atlassian.plugin.spring.scanner.annotation.imports.JiraImport;
import com.vz.jira.config.KafkaConfig;
import com.vz.jira.domain.Defects;
import com.vz.jira.util.DefectUtil;

@Scanned
@Component
public class IssueCreatedResolvedListener implements InitializingBean, DisposableBean {

    private static final Logger log = LoggerFactory.getLogger(IssueCreatedResolvedListener.class);
    
    @JiraImport
    private final EventPublisher eventPublisher;
    private ObjectMapper mapper = new ObjectMapper();
    private KafkaTemplate<Long, String> template= new KafkaConfig().kafkaTemplate();
    
    @Autowired
    public IssueCreatedResolvedListener(@JiraImport EventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }
    
    @EventListener
    public void onIssueEvent(IssueEvent issueEvent) {
        
    try{    
       Long eventTypeId = issueEvent.getEventTypeId();
       Issue issue = issueEvent.getIssue();
       
       if(issue!=null){
           Defects defect = DefectUtil.getDesiredIssueDetails(issue); //extract necessary details to be sent to Kafka
           ListenableFuture<SendResult<Long, String>> future=template.send("issue",issue.getId(),mapper.writeValueAsString(defect));
           future.addCallback(new ListenableFutureCallback<SendResult<Long, String>>() {

            @Override
            public void onSuccess(SendResult<Long, String> result) {
                handleSuccess(eventTypeId,issue.getDescription(),result);
            }

            @Override
            public void onFailure(Throwable ex) {
                try {
                    handleFailure(eventTypeId,issue.getDescription(),ex);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
       
           });
       }
    }catch (Exception e){
        e.printStackTrace();
    }
      
       
    }
    
    protected void handleFailure(Long key, String value, Throwable ex) throws Throwable {
        System.out.println("Error sending message & the exception is: {} "+ ex.getMessage());   
        throw ex;
    }

    protected void handleSuccess(Long key, String value, SendResult<Long, String> result) {
        System.out.println("Message Sent Successfully for key: "+key+" value "+value+" partiotion is: "+ result.getRecordMetadata().partition() );
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("Disabling plugin");
        eventPublisher.unregister(this);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Enabling plugin");
        eventPublisher.register(this);      
    }
}