From 806d2d87b7ef875e8810ab24a5ab2cd3d192a6dd Mon Sep 17 00:00:00 2001 From: KevinGilmore Date: Wed, 5 Apr 2017 13:12:33 -0500 Subject: [PATCH] BAEL-415: Custom Scope in Spring (#1578) * Add files via upload * Update pom.xml * Update RunGuice.java * Update Communication.java * Update CommunicationMode.java * Update DefaultCommunicator.java * Update EmailCommunicationMode.java * Update IMCommunicationMode.java * Update SMSCommunicationMode.java * Update MessageLogger.java * Update MessageSentLoggable.java * Update AOPModule.java * Update BasicModule.java * Update CommunicationModel.java * Update Communicator.java * Update BasicModule.java * Update RunGuice.java * Update MessageLogger.java * Update Communicator.java * Update pom.xml * BAEL-278: Updated README.md * BAEL-554: Add and update README.md files * Update pom.xml * Update pom.xml * Update pom.xml * BAEL-345: fixed assertion * BAEL-109: Updated README.md * BAEL-345: Added README.md * Reinstating reactor-core module in root-level pom * BAEL-393: Adding guide-intro module to root pom * BAEL-9: Updated README.md * BAEL-157: README.md updated * Changed project name * Update RunGuice.java Removed references to message logging and output * Update Communication.java Removed message logging-related code * BAEL-566: Updated README.md * New project name * BAEL-393: removing guice-intro directory * BAEL-393: renamed module guice-intro to guice in root pom.xml * BAEL-393 and BAEL-541 README.md files * BAEL-731: Updated README.md * BAEL-680: renamed test methods * BAEL-714: Updated README.md * BAEL-737: Updated README.md * BAEL-680 and BAEL-756 README.md updates * BAEL-666: Updated README * BAEL-415: Custom Scope * BAEL-415: Custom Scope - renamed classes to reflect TenantScope --- .../org/baeldung/customscope/TenantBean.java | 16 ++++ .../TenantBeanFactoryPostProcessor.java | 13 ++++ .../customscope/TenantBeansConfig.java | 21 ++++++ .../org/baeldung/customscope/TenantScope.java | 43 +++++++++++ .../customscope/TenantScopeConfig.java | 14 ++++ .../baeldung/customscope/TenantScopeTest.java | 74 +++++++++++++++++++ 6 files changed, 181 insertions(+) create mode 100644 spring-all/src/main/java/org/baeldung/customscope/TenantBean.java create mode 100644 spring-all/src/main/java/org/baeldung/customscope/TenantBeanFactoryPostProcessor.java create mode 100644 spring-all/src/main/java/org/baeldung/customscope/TenantBeansConfig.java create mode 100644 spring-all/src/main/java/org/baeldung/customscope/TenantScope.java create mode 100644 spring-all/src/main/java/org/baeldung/customscope/TenantScopeConfig.java create mode 100644 spring-all/src/test/java/org/baeldung/customscope/TenantScopeTest.java diff --git a/spring-all/src/main/java/org/baeldung/customscope/TenantBean.java b/spring-all/src/main/java/org/baeldung/customscope/TenantBean.java new file mode 100644 index 0000000000..2d3049ebb9 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/customscope/TenantBean.java @@ -0,0 +1,16 @@ +package org.baeldung.customscope; + +public class TenantBean { + + private final String name; + + public TenantBean(String name) { + this.name = name; + } + + public void sayHello() { + System.out.println(String.format("Hello from %s of type %s", + this.name, + this.getClass().getName())); + } +} diff --git a/spring-all/src/main/java/org/baeldung/customscope/TenantBeanFactoryPostProcessor.java b/spring-all/src/main/java/org/baeldung/customscope/TenantBeanFactoryPostProcessor.java new file mode 100644 index 0000000000..2757399fa6 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/customscope/TenantBeanFactoryPostProcessor.java @@ -0,0 +1,13 @@ +package org.baeldung.customscope; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; + +public class TenantBeanFactoryPostProcessor implements BeanFactoryPostProcessor { + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { + factory.registerScope("tenant", new TenantScope()); + } +} diff --git a/spring-all/src/main/java/org/baeldung/customscope/TenantBeansConfig.java b/spring-all/src/main/java/org/baeldung/customscope/TenantBeansConfig.java new file mode 100644 index 0000000000..0e21ad9344 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/customscope/TenantBeansConfig.java @@ -0,0 +1,21 @@ +package org.baeldung.customscope; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +@Configuration +public class TenantBeansConfig { + + @Scope(scopeName = "tenant") + @Bean + public TenantBean foo() { + return new TenantBean("foo"); + } + + @Scope(scopeName = "tenant") + @Bean + public TenantBean bar() { + return new TenantBean("bar"); + } +} diff --git a/spring-all/src/main/java/org/baeldung/customscope/TenantScope.java b/spring-all/src/main/java/org/baeldung/customscope/TenantScope.java new file mode 100644 index 0000000000..062d7ee890 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/customscope/TenantScope.java @@ -0,0 +1,43 @@ +package org.baeldung.customscope; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.config.Scope; + +public class TenantScope implements Scope { + + private Map scopedObjects = Collections.synchronizedMap(new HashMap()); + private Map destructionCallbacks = Collections.synchronizedMap(new HashMap()); + + @Override + public Object get(String name, ObjectFactory objectFactory) { + if(!scopedObjects.containsKey(name)) { + scopedObjects.put(name, objectFactory.getObject()); + } + return scopedObjects.get(name); + } + + @Override + public Object remove(String name) { + destructionCallbacks.remove(name); + return scopedObjects.remove(name); + } + + @Override + public void registerDestructionCallback(String name, Runnable callback) { + destructionCallbacks.put(name, callback); + } + + @Override + public Object resolveContextualObject(String key) { + return null; + } + + @Override + public String getConversationId() { + return "tenant"; + } +} diff --git a/spring-all/src/main/java/org/baeldung/customscope/TenantScopeConfig.java b/spring-all/src/main/java/org/baeldung/customscope/TenantScopeConfig.java new file mode 100644 index 0000000000..d1159b0f60 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/customscope/TenantScopeConfig.java @@ -0,0 +1,14 @@ +package org.baeldung.customscope; + +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class TenantScopeConfig { + + @Bean + public static BeanFactoryPostProcessor beanFactoryPostProcessor() { + return new TenantBeanFactoryPostProcessor(); + } +} diff --git a/spring-all/src/test/java/org/baeldung/customscope/TenantScopeTest.java b/spring-all/src/test/java/org/baeldung/customscope/TenantScopeTest.java new file mode 100644 index 0000000000..641e57bffd --- /dev/null +++ b/spring-all/src/test/java/org/baeldung/customscope/TenantScopeTest.java @@ -0,0 +1,74 @@ +package org.baeldung.customscope; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Map; + +import org.junit.Test; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +public class TenantScopeTest { + + @Test + public final void whenRegisterScopeAndBeans_thenContextContainsFooAndBar() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + try{ + ctx.register(TenantScopeConfig.class); + ctx.register(TenantBeansConfig.class); + ctx.refresh(); + + TenantBean foo = (TenantBean) ctx.getBean("foo", TenantBean.class); + foo.sayHello(); + TenantBean bar = (TenantBean) ctx.getBean("bar", TenantBean.class); + bar.sayHello(); + Map foos = ctx.getBeansOfType(TenantBean.class); + + assertThat(foo, not(equalTo(bar))); + assertThat(foos.size(), equalTo(2)); + assertTrue(foos.containsValue(foo)); + assertTrue(foos.containsValue(bar)); + + BeanDefinition fooDefinition = ctx.getBeanDefinition("foo"); + BeanDefinition barDefinition = ctx.getBeanDefinition("bar"); + + assertThat(fooDefinition.getScope(), equalTo("tenant")); + assertThat(barDefinition.getScope(), equalTo("tenant")); + } + finally { + ctx.close(); + } + } + + @Test + public final void whenComponentScan_thenContextContainsFooAndBar() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + try{ + ctx.scan("org.baeldung.customscope"); + ctx.refresh(); + + TenantBean foo = (TenantBean) ctx.getBean("foo", TenantBean.class); + foo.sayHello(); + TenantBean bar = (TenantBean) ctx.getBean("bar", TenantBean.class); + bar.sayHello(); + Map foos = ctx.getBeansOfType(TenantBean.class); + + assertThat(foo, not(equalTo(bar))); + assertThat(foos.size(), equalTo(2)); + assertTrue(foos.containsValue(foo)); + assertTrue(foos.containsValue(bar)); + + BeanDefinition fooDefinition = ctx.getBeanDefinition("foo"); + BeanDefinition barDefinition = ctx.getBeanDefinition("bar"); + + assertThat(fooDefinition.getScope(), equalTo("tenant")); + assertThat(barDefinition.getScope(), equalTo("tenant")); + } + finally { + ctx.close(); + } + } +}