Last updated Oct 8, 2024

Creating plugin module instances

Overview

When specifying an implementation of a plugin module, you can specify the class name that the plugin framework should resolve, instantiate, and inject for you. Instances are created per usage (prototype-scope) and Spring injection will happen via autodetection autowire mode, which tries constructor injection, falling back to setter injection by type.

In Atlassian Plugin Framework 2.5 and later, the instantiation of a plugin module has been improved to give you full control how your module classes will be created via a new optional prefix-based, pluggable PrefixModuleFactory interface. Out of the box, the framework ships with support for the "bean:" prefix that allows you to refer to a Spring bean by ID instead of specifying a classname in the module descriptor. This gives you complete control over the creation, scope, and injection of your plugin modules.

Everything from here down is available in

Atlassian Plugin Framework 2.5 and later.

For example, if you wanted to instantiate a class, you could specify a servlet class via:

1
2
<servlet key="myServlet" class="class:com.example.MyServlet" />

Since the "class" prefix is the default, you could also configure the Servlet via:

1
2
<servlet key="myServlet" class="com.example.MyServlet" />

The following prefixes are supported:

Prefix

Description

class

Instantiates the class via Spring using the autodetect autowire mode

Default: true

bean

Looks up the specified bean ID in the Spring context

Using the "bean" Prefix

Before you can use the "bean" prefix, you must create a bean that lives in the Spring context. This bean can be specified via the <component> module type or in a custom Spring XML file living in META-INF/spring. When using Spring XML directly, you have full control over the creation, scope, and injection of the bean. Reasons you may want to use the "bean" prefix include:

  • Want to use constructor injection even if you have a default constructor.
  • Want to manually configure the beans to inject, including constants.
  • Want to share a module instance with components.
  • Want to customise the scope of the module instance. But be aware that the descriptor may cache the instance later.

Examples

Making a module instance available to other components or plugin modules

In atlassian-plugin.xml:

1
2
<component key="myServlet" class="com.example.MyServlet" />
<servlet key="myServlet" class="bean:myServlet" />

Using "byName" setter injection

In META-INF/spring/myPlugin.xml:

1
2
<bean id="myServlet" class="com.example.MyServlet" autowire="byName"/>

In atlassian-plugin.xml:

1
2
<servlet key="myServlet" class="bean:myServlet" />

Creating a New Prefix

You can create your own prefix for further control over the creation of module instances. This technique can be used to do things like delegating the creation to a scripting engine or automatically wrapping all module instances in proxies.

Example

Let's say we want to create a new prefix called "named", which instantiates all module instances via a single argument constructor that expects the name of the plugin.

Step 1. Create a PrefixModuleFactory instance

Our NamedPrefixModuleFactory loads the class then instantiates its constructor with the plugin key:

1
2
public class NamedPrefixModuleFactory implements PrefixModuleFactory
{
    public String getPrefix()
    {
        return "named";
    }

    public <T> T createModule(String name, ModuleDescriptor<T> moduleDescriptor) throws PluginParseException
    {
        try
        {
            Class clazz = getClass().getClassLoader().loadClass(name);
            return (T) clazz.getConstructor(String.class).newInstance(moduleDescriptor.getPluginKey());
        }
        catch (Exception e)
        {
            throw new RuntimeException("Obviously non-production code here...", e);
        }
    }
}

Step 2. Expose it as a component

Just by exposing the NamedPrefixModuleFactory as a component, or more specifically, as a bean in our BeanFactory, the plugin framework will pick it up and use it for plugin module prefix resolution:

1
2
<component key="namedPrefix" class="com.example.NamedPrefixModuleFactory" />

Step 3. Use the new prefix

The prefix is now able to be used by plugin modules that expect objects like the servlet module type:

1
2
<servlet key="myServlet" class="named:com.example.MyServlet" />

Common Coding Tasks
Plugin Modules

Rate this page: