From df1373aa8150e0462f20df5be671e98cd8fd330b Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Sun, 12 Jan 2014 17:54:52 +0100 Subject: [PATCH] DATACMNS-416 - Added means to enforce eager instantiation of CDI repositories. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CDI extension now eagerly instantiates repository beans that are annotated with the newly introduced @Eager annotation. This is necessary to prevent the initialization procedure from interfering with potentially already executed business logic. To achieve this CdiRepositoryExtensionSupport provides a new method registerBean(…) that has to be called by store implementations. The extension will then keep track of beans that require eager initialization and trigger it when the container has finished validation. --- .../repository/cdi/CdiRepositoryBean.java | 23 ++++++++---- .../cdi/CdiRepositoryExtensionSupport.java | 36 ++++++++++++++++++ .../data/repository/cdi/Eager.java | 37 +++++++++++++++++++ .../repository/cdi/DummyCdiExtension.java | 4 +- 4 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/springframework/data/repository/cdi/Eager.java diff --git a/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryBean.java b/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryBean.java index b73477e11..448b597e9 100644 --- a/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryBean.java +++ b/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryBean.java @@ -53,6 +53,8 @@ public abstract class CdiRepositoryBean implements Bean, PassivationCapabl private final BeanManager beanManager; private final String passivationId; + private transient T repoInstance; + /** * Creates a new {@link CdiRepositoryBean}. * @@ -107,11 +109,6 @@ public abstract class CdiRepositoryBean implements Bean, PassivationCapabl interfaces.add(repositoryType); interfaces.addAll(Arrays.asList(repositoryType.getInterfaces())); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format("Declaring types '%s' for repository '%s'.", interfaces.toString(), - repositoryType.getName())); - } - return new HashSet(interfaces); } @@ -128,17 +125,27 @@ public abstract class CdiRepositoryBean implements Bean, PassivationCapabl return (S) beanManager.getReference(bean, type, creationalContext); } + /** + * Forces the initialization of bean target. + */ + public final void initialize() { + create(beanManager.createCreationalContext(this)); + } + /* * (non-Javadoc) * @see javax.enterprise.context.spi.Contextual#create(javax.enterprise.context.spi.CreationalContext) */ public final T create(CreationalContext creationalContext) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format("Creating bean instance for repository type '%s'.", repositoryType.getName())); + if (this.repoInstance != null) { + LOGGER.debug("Returning eagerly created CDI repository instance for {}.", repositoryType.getName()); + return this.repoInstance; } - return create(creationalContext, repositoryType); + LOGGER.debug("Creating CDI repository bean instance for {}.", repositoryType.getName()); + this.repoInstance = create(creationalContext, repositoryType); + return repoInstance; } /* diff --git a/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryExtensionSupport.java b/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryExtensionSupport.java index c65b52b0b..df211f8a5 100644 --- a/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryExtensionSupport.java +++ b/src/main/java/org/springframework/data/repository/cdi/CdiRepositoryExtensionSupport.java @@ -25,7 +25,9 @@ import java.util.Set; import javax.enterprise.event.Observes; import javax.enterprise.inject.Any; import javax.enterprise.inject.Default; +import javax.enterprise.inject.spi.AfterDeploymentValidation; import javax.enterprise.inject.spi.AnnotatedType; +import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.ProcessAnnotatedType; import javax.enterprise.util.AnnotationLiteral; @@ -33,6 +35,7 @@ import javax.inject.Qualifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.repository.NoRepositoryBean; import org.springframework.data.repository.Repository; import org.springframework.data.repository.RepositoryDefinition; @@ -48,6 +51,7 @@ public abstract class CdiRepositoryExtensionSupport implements Extension { private static final Logger LOGGER = LoggerFactory.getLogger(CdiRepositoryExtensionSupport.class); private final Map, Set> repositoryTypes = new HashMap, Set>(); + private final Set> eagerRepositories = new HashSet>(); /** * Implementation of a an observer which checks for Spring Data repository types and stores them in @@ -115,6 +119,22 @@ public abstract class CdiRepositoryExtensionSupport implements Extension { return qualifiers; } + /** + * Triggers the eager initialization of beans registered for that behavior. + * + * @param event must not be {@literal null}. + * @param manager must not be {@literal null}. + * @see #registerBean(CdiRepositoryBean) + */ + void afterDeploymentValidation(@Observes AfterDeploymentValidation event, BeanManager manager) { + + for (CdiRepositoryBean bean : eagerRepositories) { + + LOGGER.debug("Eagerly instantiating CDI repository bean for {}.", bean.getBeanClass()); + bean.initialize(); + } + } + /** * Provides access to all repository types as well as their qualifiers. * @@ -124,6 +144,22 @@ public abstract class CdiRepositoryExtensionSupport implements Extension { return repositoryTypes.entrySet(); } + /** + * Registers the given {@link CdiRepositoryBean} for further general treatment by the infrastructure. In particular, + * this will cause repositories to be instantiated eagerly if marked as such. + * + * @param bean must not be {@literal null}. + * @see #afterDeploymentValidation(AfterDeploymentValidation, BeanManager) + */ + protected void registerBean(CdiRepositoryBean bean) { + + Class repositoryInterface = bean.getBeanClass(); + + if (AnnotationUtils.findAnnotation(repositoryInterface, Eager.class) != null) { + this.eagerRepositories.add(bean); + } + } + @SuppressWarnings("all") static class DefaultAnnotationLiteral extends AnnotationLiteral implements Default { diff --git a/src/main/java/org/springframework/data/repository/cdi/Eager.java b/src/main/java/org/springframework/data/repository/cdi/Eager.java new file mode 100644 index 000000000..3350176f7 --- /dev/null +++ b/src/main/java/org/springframework/data/repository/cdi/Eager.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.repository.cdi; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to mark repository interfaces to be instantiated eagerly in a CDI context. + * + * @author Oliver Gierke + * @since 1.7 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE }) +@Inherited +public @interface Eager { + +} diff --git a/src/test/java/org/springframework/data/repository/cdi/DummyCdiExtension.java b/src/test/java/org/springframework/data/repository/cdi/DummyCdiExtension.java index 389589b91..767e23734 100644 --- a/src/test/java/org/springframework/data/repository/cdi/DummyCdiExtension.java +++ b/src/test/java/org/springframework/data/repository/cdi/DummyCdiExtension.java @@ -40,7 +40,9 @@ public class DummyCdiExtension extends CdiRepositoryExtensionSupport { @SuppressWarnings({ "rawtypes", "unchecked" }) void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) { for (Entry, Set> type : getRepositoryTypes()) { - afterBeanDiscovery.addBean(new DummyCdiRepositoryBean(type.getValue(), type.getKey(), beanManager)); + DummyCdiRepositoryBean bean = new DummyCdiRepositoryBean(type.getValue(), type.getKey(), beanManager); + registerBean(bean); + afterBeanDiscovery.addBean(bean); } }