Services
Last updated on 30th September, 2017 by George Taylor
Services in AEM run in the OSGI framework. By default they don't have access to the users session as they may not have been called from within a user request.
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.References;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import com.sample.core.services.Externalizer;
@Component(immediate = true, label = "Externalizer Service", description = "Custom AEM service for getting external urls", metatype = true, enabled = true)
@Service
@Properties({
@Property(name = "author", label = "Author", description = "The author url"),
@Property(name = "dispatcher", label = "Dispatcher", description = "The dispatcher url") })
private static final String HTTP_LOCALHOST = "http://localhost";
private static final String HTTP_LOCALHOST_4502 = "http://localhost:4502";
private Map<Long, ExternalizerConfigAmendment^gt; amendments = new HashMap><();
private List<ExternalizerConfigAmendment> sortedMappings = new ArrayList<>();
@Activate
@Modified
void configure(final Map<String, Object> config) {
private void updateMappings() {
for (final ExternalizerConfigAmendment amendment : this.amendments.values()) {
Collections.sort(sortedMappings);
@Override
public String getAuthor(Resource page) {
return HTTP_LOCALHOST_4502;
@Override
public String getDispatcher(Resource page) {
return HTTP_LOCALHOST;
protected void bindAmendment(final ExternalizerConfigAmendment amendment, final Map<String, Object> props) {
synchronized (this.amendments) {
this.updateMappings();
protected void unbindAmendment(final ExternalizerConfigAmendment amendment, final Map<String, Object> props) {
synchronized (this.amendments) {
protected void updateAmendment(final ExternalizerConfigAmendment amendment, final Map<String, Object> props) {
As mentioned on the OSGI Components page a service is a special type of component that will generally have some logic.
The type of service is defined in the Service annotation, In the above service the annotation is empty so it defines it as a service of itself only, but you can define a service of specific type as show in the Listeners page, an event listener is of type EventHandler
This is useful for when you want to get a reference to a service, you can lookup all services registered for a specific type of class using the slingScriptHelper's getServices method.
While usually a service supports a single type, it is possible to have a service that supports multiple types as in the following example
While this is possible, and have may good use when the class has multiple entry points, it is recommended that each class has a specific purpose so should only be used as a single type.
Because a service is a component it means that you can reference other components using the reference annotation to get access to another component
private JobManager jobManager;
While you can write a service that doesn't have an interface, it is considered bad practice and all services should implement an interface that the service annotation references