How do I inject beans into a scope implementation? - java

I'm writing my own scope (i.e. a class which implements org.springframework.beans.factory.config.Scope) and I need some beans injected. How do I do that?
Background: Spring must create all scope beans first so that I can define which beans go into the scope. But what about beans that I need to build the scope in the first place?

I came up with this workaround which seems to be pretty safe but I'd like to hear comments (or maybe my answer gives you some better ideas):
Define the scope and give it setters (instead of using #Autowired)
Create a "scope configurer" bean:
public CustomScopeConfigurer {
#Autowired private Foo foo;
private CustomScope scope;
public CustomScopeConfigurer( CustomScope scope ) {
this.scope = scope;
}
#PostConstruct
public void initScope() {
scope.setFoo( foo );
}
}
This configurer bean must not be lazy.
Reasoning:
The scope itself can't use autowiring because it is created before the first bean. While it might be created later, you can be sure that it will be created before every other bean. So autowiring can't work reliably.
The configurer bean will be created alongside all the other beans but after the scope. So autowiring will work for it.
Since the configurer bean isn't initialized lazy, it will be created before the rest of the application can see the application context. This means that no beans for the scope (i.e. beans with #Scope("custom")) can have been created at this time - the scope can't be "active", yet -> Spring won't have tried to put any beans into it, yet.
The scope itself is usually created as a static constant somewhere. That's why we have to pass it as an argument to the constructor.

You can do that very simply.
Consider the below Custom scope class:
package com.way2learn;
import java.util.Map;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
public class MyCustomScope implements Scope{
private Map<String, Object> scope;
public void setScope(Map<String, Object> scope) {
this.scope = scope;
}
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
checkAndClear();
Object bean=scope.get(name);
if(bean==null){
bean=objectFactory.getObject();
scope.put(name,bean);
}
return bean;
}
private void checkAndClear() {
//Some logic to check condition and clear the scope
}
//optional methods
#Override
public Object remove(String name) {
// TODO Auto-generated method stub
return null;
}
#Override
public void registerDestructionCallback(String name, Runnable callback) {
}
#Override
public Object resolveContextualObject(String key) {
// TODO Auto-generated method stub
return null;
}
#Override
public String getConversationId() {
// TODO Auto-generated method stub
return null;
}
}
It has dependency on java.util.Map.
You can not autowire using #Autowired it as #Autowired annotation works after AutoWiredAnnotationBeanPostProcessor only.
But Custom scopes will be registered before AutoWiredAnnotationBeanPostProcessor.
So you can manually inject Map into MyCustomScope class as below:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">
<util:map key-type="java.lang.String" value-type="java.lang.Object" id="custScopeMap"/>
<bean id="myCustomScope" class="com.way2learn.MyCustomScope">
<property name="scope" ref="custScopeMap"/>
</bean>
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="myScope" value-ref="myCustomScope"/>
</map>
</property>
</bean>
</beans>
I tried it. It works fine. And I found a bug in Aaron Digulla's answer i.e.
Consider the below scenario: First Spring's CustomScopeConfigurer bean will be created, immediately CustomScope bean will be created and now our custom scope is ready to use. After some time Aaron Digulla's CustomScopeConfigurer will be created which initializes foo into CustomScope. But what happenes if some custom scoped beans are created after CustomScope registration and before Aaron Digulla's CustomScopeConfigurer bean creation? For those beans there will be not foo in the CustomScope bean.

Related

#scope - spring - setting scope "prototype" using annotations, behaves like singleton. Where am i going wrong?

When i try to use #scope("prototype") over a class, I see it behaves similar to "singleton" I am not sure where I am wrong. Any help on this is much appreciated.
Employee class - setting scope - prototype
import org.springframework.context.annotation.Scope;
#Scope("prototype")
public class Employee {
private String emp_name;
public String getEmp_name() {
return emp_name;
}
public void setEmp_name(String emp_name) {
this.emp_name = emp_name;
}
}
Department class- setting scope - singleton
import org.springframework.context.annotation.Scope;
#Scope("singleton")
public class Department {
private String dep_name;
public String getDep_name() {
return dep_name;
}
public void setDep_name(String dep_name) {
this.dep_name = dep_name;
}
}
Beans.xml
<context:component-scan base-package="com"/>
<!-- Scope Annotations -->
<bean id="dep_scope" class="com.scope.annotation.Department" >
</bean>
<bean id="emp_scope" class="com.scope.annotation.Employee" >
</bean>
Main App
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Employee emp = (Employee) context.getBean("emp_scope");
emp.setEmp_name("Saro");
System.out.println("first"+emp.getEmp_name());
Employee emp2 = (Employee) context.getBean("emp_scope");
System.out.println("second"+emp2.getEmp_name());
Department dep = (Department) context.getBean("dep_scope");
dep.setDep_name("Maths");
System.out.println("first"+dep.getDep_name());
Department dep2 = (Department) context.getBean("dep_scope");
System.out.println("second"+dep2.getDep_name());
}
}
Output :
firstSaro
secondSaro
firstMaths
secondMaths
I expected secondnull instead of secondSaro
Just try to define scope in beans.xml file in bean tag.... you are using both annotation and xml ... just use either..
Or you can try to define bean using annotation ...
for that you can use #Bean annotation.
#Configuration
public class Config {
#Bean(scope=DefaultScopes.PROTOTYPE)
public TestBean testBean(){
return new TestBean();
}
}
And In your main logic you can use bellow code
TestBean testBean = ctx.getBean(TestBean.class);
It behaves as a singleton because this is the ways it is defined in the your xml conf. Default scope is singleton, prototype should be declares like follows
<bean id="dep_scope" class="com.scope.annotation.Department" scope="prototype">
</bean>
If you want to use annotations, javadoc states that #Scope should be used in conjunction with #Component, like this
#Component
#Scope("prototype")
public class Employee {
//...
}
public class ExampleUsingEmployee {
#Inject
private Employee enployee; //will be automatically injected by spring
// ... do other stuff
}
You should avoid (if possible) using both xml and annotations.
You have put
context:component-scan base-package="com"
which will try to instantiate beans if they are annotated with #Component or the other bean annotations like #Service, etc. But this does not make spring process the other annotations configuration.
if you want to process the other spring annotations you must register
context:annotation-config> .
too in order to ask spring to look for the annotations in the defined beans.
in summary
context:component-scan : will instantiate beans within the package if they are annotated with suitable annotation
context:annotation-config : will process the annotations in the configured beans irrespective of whether they are defined via annotations or xml.

Defining the request scope as prototype for integration tests

When writing integration tests with Spring 3.1, I usually define the request scope to be a SimpleThreadScope, with the following XML context configuration:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="request">
<bean class="org.springframework.context.support.SimpleThreadScope" />
</entry>
</map>
</property>
</bean>
To define the request scope to be backed by a prototype scope implementation, I thought to change the class to be an implementation of the prototype scope. However I was not able to locate any.
Looking at the Scope Interface Javadoc, in the section All Known Implementing Classes, I see listed: AbstractRequestAttributesScope, PortletContextScope, RequestScope, ServletContextScope, SessionScope, SimpleThreadScope... nothing that looks like a prototype scope.
How can I define the request scope as prototype for integration tests?
UPDATE: I've managed to make my integration tests pass by creating my own prototype scope, which I've defined as follow, so my question now is, whether the following implementation is correct, or it has to be fixed.
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
public class PrototypeScope implements Scope {
private static final Log logger = LogFactory.getLog(PrototypeScope.class);
public Object get(String name, ObjectFactory objectFactory) {
return objectFactory.getObject();
}
public Object remove(String name) {
return null;
}
public void registerDestructionCallback(String name, Runnable callback) {
logger.warn("PrototypeScope does not support destruction callbacks. "
+ "Consider using a RequestScope in a Web environment.");
}
public Object resolveContextualObject(String key) {
return null;
}
public String getConversationId() {
return Thread.currentThread().getName();
}
}
UPDATE 2: I am using TestNG and my Integration tests look like this:
#Test
#ContextConfiguration(locations = { "classpath:META-INF/spring/test-context.xml" })
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class MyIntegrationTest extends AbstractTransactionalTestNGSpringContextTests {
#Resource
private MyBeanThatShouldBePrototype bean;
#Transactional
public void testCase() {
...
In fact it's working in a different way - Spring checks if bean is a prototype, and then clones its definition and just populate new bean, so there is no backing class for holding such beans. If you want to look at the implementation please visit:
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean and you will find:
if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
If you want to use prototype scope in tests you can just manually create this bean by invoking new MyObjectThatShouldBePrototype() and then configure it as a Spring bean by using AutowireCapableBeanFactory (injected/autowired into your test):
#Autowired
AutowireCapableBeanFactory beanFactory;
public MyObjectThatShouldBePrototype getBean() {
MyObjectThatShouldBePrototype bean = new MyObjectThatShouldBePrototype();
beanFactory.autowireBean(bean);
return bean;
}
Of course there are several ways to create beans - you can find then here http://www.kubrynski.com/2013/09/injecting-spring-dependencies-into-non.html
Something like this is not working for you?
#Test
#ContextConfiguration(locations = { "classpath:META-INF/spring/test-context.xml" },
classes = MyIntegrationTest.TestConfig.class)
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class MyIntegrationTest extends AbstractTransactionalTestNGSpringContextTests {
#Resource
private MyBeanThatShouldBePrototype bean; // protype bean produced by spring
#Transactional
public void testCase() {
...
}
#Configuration
public static class TestConfig {
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public MyBeanThatShouldBePrototype myBeanThatShouldBePrototype() {
return new MyBeanThatShouldBePrototype();
}
}
}
Probably you could go another way?
What about writing a beanfactorypostprocessor that changes the request scoped bean candidates to prototype instead?
I havent tried it myself but you should be able to apply this to any bean declared as request scoped and set the prototype flag.
In the spring context for your unit tests you define this processor and in the context for integration tests this postprocessor would not be around.

AOP with Spring 3 using Annotations

I am trying to get Aspect working with Spring 3 and annotations.
#Aspect
public class AttributeAspect {
#Pointcut("#annotation(com.mak.selective.annotation.Attribute)")
public void process(){
System.out.println("Inside Process ....");
}
#Around("process()")
public void processAttribute(){
System.out.println("Inside Actual Aspect ..");
}
}
XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<aop:aspectj-autoproxy proxy-target-class="false" />
<context:component-scan base-package="com.mak.selective.annotation.*" />
<bean name="attribute" class="com.mak.selective.annotation.AttributeAspect"/>
</beans>
MY Test to test the Aspect:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/springcontext/*.xml")
public class AttributeTest {
#Attribute(tableName = "firstTable", columnName = "New Column")
private void getAttribute() {
System.out.println("Inside Attribute call...");
}
#Test
public void testAttributeAspect() {
getAttribute();
}
}
With this code i can only see "Inside Attribute call..." but nothing from Aspect.
Please guide.
Got this working by making a new Object (Component) and injected to the Junit test class.
Good to see that you got it working from XML, but you could have also done it from annotations.
The issue is that the #Aspect annotation is not a Spring stereotype, so the scanner is not registering the aspect as a Spring Bean. Just add either #Service or #Component above or below #Aspect and it will be registered.
Also, either directly name the bean (e.g., #Service("myNamedService")) or have it implement an interface (e.g., public class AttributeAspect implements IAspect {), as per standard Spring design.
You need to use real AspectJ if you want to intercept invocations of methods within the same bean form where it is invoked. (What you have done, should work if the method testAttributeAspect() is located in an other bean.)
How to do real AspectJ?
Using the AspectJ compiler and weaver enables use of the full AspectJ language, and is discussed in Section 7.8, “Using AspectJ with Spring applications”.
#See Spring Reference
A few things:
Firstly, when you do around advice you need to write the advice method like this:
#Around(...)
public void aroundAdviceMethod(ProceedingJoinPoint pjp) throws Throwable {
try {
System.out.println("before...");
pjp.proceed();
}
finally {
System.out.println("After...");
}
}
But also (and this at least applies when you're using proxies, not entirely sure in your case), the method you're putting advice on needs to be public (yours isn't), spring managed (via #Component or otherwise) and called external from the class so the proxy can take effect (also not the case in your example). So you need something like this:
#Component
public class SomeClass {
#Attribute
public void someMethodCall() {
System.out.println("In method call");
}
}
public class SomeUnitTest {
#Autowired SomeClass someClass;
#Test
public void testAspect() {
someClass.someMethodCall();
}
}

Prototype scope not working

I've created a prototype scoped bean in my application and I'm injecting that to another bean using a setter. But when I'm using the injected bean in my class it is always using the same instance instead of new instance every time.
Here is a snapshot of the code
<bean name="prototypeScope" Class="A" scope="prototype">
</bean>
<bean Class="Consumer">
<property name="a" ref="prototypeScope" />
</bean>
public class Consumer{
privare A a;
public void setA(A a){
this.a = a;
}
public void consume(){
a.doSomething();
}
}
Regards
It is an common mistake related to prototype scoped beans.
A new instance of the prototype scoped bean will be created only when we request a copy of the bean from the application context, not every time we call a method on the instance.
In your case you are injecting the prototype scoped bean to another bean using the setter of the later, so then the second class is created a new instance of the prototype scoped bean will be created. But it will use the same instance as long as it is replace by another instace mannualy by you.
If you want a new instance of the prototype scoped bean during a particular operation like a method call, you have to get a new instance of the bean from the application content.
Ex:
<bean name="prototypeScope" Class="A" scope="prototype">
</bean>
<bean Class="Consumer">
</bean>
Java code:
public class Consumer implements ApplicationContextAware{
privare ApplicationContext context;
public void setApplicationContext(ApplicationContext context){
this.context = context;
}
public void consume(){
A a = context.getBean("prototypeScope", A.class);
a.doSomething();
}
}
In this example when ever the consume method is called a new instance of class A is created.
There are two main ways to deal with the Singleton-Bean-has-Prototype-dependency problem.
One is tight coupling to the applicationContext, as in Ram's answer, the other is Lookup Method Injection.
Basically, you make your bean class abstract and add an abstract method for the dependency, something like this:
public abstract class MyBean{
public abstract MyService lookupService();
}
Then you add a bean definition something like this:
<bean id="myBean" class="fiona.apple.sucks.MyBean">
<!-- sorry, just wanted to insert sucks after Spring's fiona apple example,
didn't think about the connotations :-) -->
<lookup-method name="lookupService"/>
</bean>
Now Spring will create a CGLib subclass of your bean class that will return a new Prototype instance for every time you call myBean.lookupService().
I used such approach once..
First I declared a bean
<bean id="notSingelton" class="com.Foo" singleton="false" />
Then made an interface
public interface FooFactory {
Foo make(String name);
}
wrapped it into ServiceLocatorFactoryBean
<bean id="fooFactory"
class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface" value="com.FooFactory" />
</bean>
<bean id="consumer" class="com.Consumer">
<constructor-arg ref="fooFactory" />
</bean>
And consumer class looked something like that:
public class Consumer {
private FooFactory fooFactory;
public Consumer(FooFactory fooFactory) {
this.fooFactory = fooFactory;
}
public void consume(){
Foo foo = fooFactory.make("notSingelton");
foo.doSomething();
}
}

How to collect and inject all beans of a given type in Spring XML configuration

One of the strongest accents of the Spring framework is the Dependency Injection concept. I understand one of the advices behind that is to separate general high-level mechanism from low-level details (as announced by Dependency Inversion Principle).
Technically, that boils down to having a bean implementation to know as little as possible about a bean being injected as a dependency, e.g.
public class PrintOutBean {
private LogicBean logicBean;
public void action() {
System.out.println(logicBean.humanReadableDetails());
}
//...
}
<bean class="PrintOutBean">
<property name="loginBean" ref="ShoppingCartBean"/>
</bean>
But what if I wanted to a have a high-level mechanism operating on multiple dependent beans?
public class MenuManagementBean {
private Collection<Option> options;
public void printOut() {
for (Option option:options) {
// do something for option
}
//...
}
}
I know one solution would be to use #Autowired annotation in the singleton bean, that is...
#Autowired
private Collection<Option> options;
But doesn't it violate the separation principle? Why do I have to specify what dependents to take in the very same place I use them (i.e. MenuManagementBean class in my example)?
Is there a way to inject collections of beans in the XML configuration like this (without any annotation in the MMB class)?
<bean class="MenuManagementBean">
<property name="options">
<xxx:autowire by-type="MyOptionImpl"/>
</property>
</bean>
Old question and in Spring 3.1 it is possible:
public class PluginPrototypeTest extends ASpringWebTest {
#Autowired
Collection<IDummyRepo> repos;
#Test
public void cacheTest() {
assertNotNull(repos);
assertEquals(2, repos.size());
for(IDummyRepo r: repos){
System.out.println(r.getName());
}
}
}
#Repository
public class DummyRepo implements IDummyRepo {
#Override
public String getName(){
return "DummyRepo";
}
}
#Repository
public class DummyRepo2 implements IDummyRepo {
#Override
public String getName(){
return "DummyRepo2";
}
}
There's no out-of-the-box facility to do this, no. However, if you want a way of collecting all beans of a given type into a collection, without using an #Autowired list, then it's easy to write a custom FactoryBean to do it for you:
public class BeanListFactoryBean<T> extends AbstractFactoryBean<Collection<T>> {
private Class<T> beanType;
private #Autowired ListableBeanFactory beanFactory;
#Required
public void setBeanType(Class<T> beanType) {
this.beanType = beanType;
}
#Override
protected Collection<T> createInstance() throws Exception {
return beanFactory.getBeansOfType(beanType).values();
}
#Override
public Class<?> getObjectType() {
return Collection.class;
}
}
and then
<bean class="MenuManagementBean">
<property name="options">
<bean class="BeanListFactoryBean">
<property name="beanType" class="MyOptionImpl.class"/>
</bean>
</property>
</bean>
However, this all seems like a lot of effort to avoid putting #Autowired in your original class. It's not much of a violation of SoC, if it is at all - there's no compiltime dependency, and no knowledge of where the options are coming from.
Alternative to #Autowired, using a context file: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-autowire
So you'd have:
<bean class="MenuManagementBean" autowire="byType" />
Other properties can be specified, as normal, and that would override the autowiring only for those properties.

Categories

Resources