I have a scenario where I need to initialize a bean based on application configuration during startup. Later, due to dynamic configuration fetched based on an event, I have to update the bean.
This bean can't be updated but can only be replaced with a new instance.
Does using the new operator initialize only the local instance or will it change the bean?
#Component
public class TestComp {
#Autowired
private BeanA beanA;
public void updateBean() {
beanA = new BeanA("new value");
}
}
I referred the bean in another class and checked after I initialized it with new. It reflected the new object. But, I need a confirmation from experts if it does.
I have a scenario where I need to initialize a bean based on application configuration during startup.
It's fine. The singleton scope is a good choice here.
Later, due to dynamic configuration fetched based on an event, I have to update the bean.
It's a problem. Updating a bean in the context is a complex process: you need to remove the existing bean definition, add a new one, and update all the beans that are somehow related to the bean (reinitialise these components, refresh the context). Technically, it's possible and it has been simplified by Spring Cloud's #RefreshScope.
Does using new operator initialize only the local instance or will it change the bean?
It affects only the field in this class. No one is aware of the change. ApplicationContext#getBean still will return the old object, and all the components will be (or have already been) initialised with the old instance.
I referred the bean in another class and checked after I initialized it with new. It reflected the new object.
It can't be true. Probably, it refers to the TestComp#beanA field, not to its own BeanA field.
The solution I am suggesting is to define a custom bean scope based on the events you are receiving. It will keep the bean and the context updated.
It sounds like you want a factory instead. Below is a rough idea of what that might look like; your needs may vary.
#Component
public class BeanFactory {
private volatile BeanA beanAInstance;
public BeanA createBeanA(String value) {
if (null == beanAInstance) {
synchronized (this) {
if (null == beanAInstance) {
beanAInstance = new BeanA(value);
}
}
}
return beanAInstance;
}
public void refreshBeanA(String newValue) {
synchronized (this) {
beanAInstance = new BeanA(newValue);
}
}
}
You then wire this in, and based on configuration, you can then refresh and use the new value. Bear in mind that this would change the value you get from this bean.
Related
I have a parent bean and a child bean in the spring configuration class like attached. How can I inject the child bean dynamically into parent bean based on some condition (like feature toggle).
#Configuration
public class FooConfig {
#Bean
public void parentBean(#Qualifier("dependantBean") Object bean){
//use the correct bean at runtime
}
#Bean("dependantBean")
#FeatureToggle(feature = "feature.one", expectedToBeOn = true)
public Object test1(){
//some logic and returns a object
return new Object();
}
#Bean("dependantBean")
#FeatureToggle(feature = "feature.one",expectedToBeOn = false)
public Object test2(){
//some logic and returns a object which is different from test1 method
return new Object();
}
}
In your example it seems that the decision would be taken when the application starts.
In that case you can handle what bean gets injected with profiles (#Profile).
Side note: Use different names for the method names that create the same bean. The bean name could be the same in this case.
Another alternative could be to create a Map with the 2 dependant beans, and inject the map into the parent bean constructor.
Based on the logic you want you can use any of the two beans in the Map.
In this case use different names for the the two dependant beans.
If I have something like a jdbcTemplate that is created and managed by Spring, am I able to take that reference and pass it down to a non-spring managed class?
If I can, how do life cycle methods such as #PreDestory know if there are now these extra references which are not known to Spring floating around?
Singleton beans managed by spring are retained in the application context.
You can think about the Application Context as a map that stores key like "id" to objects that are essentially references to the beans you have.
Now you can easily pass the reference to the bean to some object not managed by spring.
class NonManagedBySpring {
private JdbcTemplate tpl;
public NonManagedBySpring(JdbcTemplate tpl) {
this.tpl = tpl;
}
public void bar() {
...
tpl.execute // or whatever
}
}
#Service // this is a spring managed service
class MyService {
#Autowired // or constructor injection, doesn't matter for the sake of this example
private JdbcTemplate tpl;
public void foo() {
NonManagedBySpring obj = new NonManagedBySpring (tpl);
obj.bar();
}
}
Now, from the point of view of lifecycle, it doesn't matter that NonManagedBySpring holds the reference on JdbcTemplate object which is a bean.
When the #PreDestroy should be called, spring checks the reference in ApplicationContext, and since as I stated at the beginning of the answer, there is a reference to singleton beans - spring will find these objects and invoke a "pre-destroy" on it.
Having said that it worth to mention that if the bean is of scope "prototype" it won't be held on Application Context and its #PreDestroy won't be called anyway, but that has nothing to do with the managed/non-managed objects. That's just how the spring works.
I'm working on a Spring application using beans of different scopes. Many beans are singletons, other request or custom scoped. Especially using those custom scopes makes it sometimes difficult to find out which scope can be safely injected into which other scope or when e.g. a Provider<T> needs to be used.
I am aware that I can just create scope proxies for all beans that are basically not singletons, but in many cases that does not seem to be necessary. For example, a bean might only be supposed to be injected into other beans of the same scope, but not everyone working on the project might be aware of that. Thus, it would be great if one could somehow prevent "misuse" of those beans, especially if one might not always recognize the mistake in time.
So my question is: Is there some way to define which scoped can be safely injected into which scope and then prevent beans with narrower scope from directly (without using Provider<T>) being injected into e.g. singleton beans?
It looks like this can be achieved fairly simple using a custom BeanPostProcessor. Within the postProcessBeforeInitialization, you can simply check the scope of the bean and the scope of all dependencies. Here is a simple example:
#Component
public class BeanScopeValidator implements BeanPostProcessor {
private final ConfigurableListableBeanFactory configurableBeanFactory;
#Autowired
public BeanScopeValidator(ConfigurableListableBeanFactory configurableBeanFactory) {
this.configurableBeanFactory = configurableBeanFactory;
}
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
String beanScope = configurableBeanFactory.getBeanDefinition(beanName).getScope();
String[] dependenciesForBean = configurableBeanFactory.getDependenciesForBean(beanName);
for (String dependencyBeanName : dependenciesForBean) {
String dependencyBeanScope = configurableBeanFactory.getBeanDefinition(dependencyBeanName).getScope();
// TODO: Check if the scopes are compatible and throw an exception
}
return bean;
}
}
This example is still very basic and is not really convenient to use. Most prominently, it lacks the capability of defining which scope can be injected into which other scope. Thus I've created a more complete example here. Using this project, the following injections are allowed by default:
Singletons can be injected into everything
Everything can be injected into prototypes
AOP proxies can be injected into everything
Everything can be injected into beans of the same scope
If you want to allow a bean to be injected into another scope, it needs to be explicitly allowed by using a respective annotation:
#Bean
#Scope("prototype")
#InjectableInto("singleton")
MyBean getMyBean(){
//...
}
I have a scope which sometimes doesn't exist when I need some bean from it. That in itself isn't a problem; I could use defaults for these cases. My problem is with autowiring. The scenarios goes roughly like this:
I have a scoped bean ICurrentLocale. It's scope is User and the scope depends on whether a user is currently logged in.
Autowire bean foo contains a field #Autowired ICurrentLocale currentLocale;
Call some methods on foo.
A user logs in. Now, I have a scope User
Call some methods on foo.
My problem is that in point #5, the autowired ICurrentLocale bean is still the same despite the fact that a new bean has created in the user's scope.
Is there a good/simple/understandable way to build a spring configuration that automatically rewires beans when a new scope is entered in the same thread?
Or maybe I can ask Spring to "refresh" the proxy?
EDIT Here is my current implementation of the scope:
#Override
public Object get( String name, final ObjectFactory<?> objectFactory ) {
CurrentUserSession currentSession = userSessionFactory.getCurrentSession();
if( currentSession == null ) {
if( isLocaleProvider( name ) ) {
return createLocaleProvider();
}
throw new BeanCreationException( "Could not create bean " + name + " the bean scope " + NAME + " can be used only after the user has signed in" );
}
Object bean = currentSession.getBean(name, objectFactory);
return bean;
}
As you can see, I create a dummy bean as long as no user is logged in. If I have a session, I look into the cache in the session. If the bean doesn't exist, yet, I use the objectFactory to create a new one.
Maybe I'm misunderstanding your question.
Your ICurrentLocale bean should be something like
#Component
#Scope(value = "user", proxy-mode = "ScopedProxyMode.TARGET_CLASS")
public class CurrentLocaleImpl implements ICurrentLocale {
...
}
or the corresponding #Bean or XML configuration.
With such configuration, Spring will create a proxy for your injection target. In other words, in
#Autowired
private ICurrentLocale currentLocale;
you won't have a CurrentLocaleImpl object, you'll have a proxy object that has a reference to the underlying BeanFactory.
5.Call some methods on foo.
My problem is that in point #5, the autowired ICurrentLocale bean is
still the same despite the fact that a new bean has created in the
user's scope.
When you invoke a method on the proxy bean, the proxy will attempt to retrieve an actual CurrentLocaleImpl object from the BeanFactory using your Scope implementation and then delegate the method call to that object. Effectively, you'll be using either the proper object, the default object, or throwing an exception.
For other people with similar problems: Make sure userSessionFactory.getCurrentSession() returns what you expect.
In my case, the user session is attached to the current thread (using ThreadLocal). Now a helper framework executed some of my code in a new background thread -> ThreadLocal returned null despite me knowing that a user was logged in.
I am converting a singleton to a Spring bean, so that if the singleton fails to initialize, then entire web application's spring context doesn't load properly.
The advantage of making the Spring context not load properly, is that people will take notice and fix the configuration during deployment itself. As opposed to using 'non-spring bean' singleton: when that throws exception during initialization, nobody notices.. until a actual user complains of missing functionality.
My changes are working as expected.. but I am not sure if I am doing the right thing.
Any thoughts?
The code looks like this:
public class MySingleton {
private static MySingleton INSTANCE = null;
private MySingleton(){}
public static MySingleton getInstance(){
if(INSTANCE == null){
synchronized(MySingleton.class){
if(INSTANCE == null){
try{
doWork()
}catch(Exception e){
throw new IllegalStateException("xyz", e);
}
INSTANCE = new MySingleton();
}
}
}
return INSTANCE;
}
private static void doWork() {
// do some work
}
}
And in the spring config xml, the bean will be defined as:
<bean id="MySingletonBean"
class="com.MySingleton"
factory-method="getInstance" lazy-init="false" singleton="true">
</bean>
Note:
Most of this is similar to the strategy discussed in this article:
http://springtips.blogspot.com/2007/06/configuration-hell-remedy-with.html
Edit 1:
The classes that use this singleton, are not spring beans themselves.. they are just non-spring pojos, that I can't convert to spring. They must rely on getInstance() method get hold of the Singleton.
Edit 2: (copying a comment I made below into this description section)
I am trying to target two things:
I want Spring to initialize the singleton. So that if the
initialization fails, then the application loading fails.
I want the other classes be able to use classes without having to rely on contextAwareObj.getBean("MySingleton")
EDIT 3 (FINAL):
I decided to make this class a singleton.. and am not making it a spring bean. If it fails to initialize, it will log something in the Log file.. hopefully the person doing deployment takes notice.... I abandoned the approach I mentioned earlier because I feel it will create a maintenance nightmare in future, so I had to pick between - singleton - or - spring bean. I chose singleton.
You must declare the INSTANCE field as volatile for double-checked locking to work correctly.
See Effective Java, Item 71.
Why are you using singleton pattern on the first place? Just let Spring create bean for you (with default singleton scope) and... use it. Of course always somebody might create the bean by hand, but this was never a problem in my case.
Dependency injection and Spring-managed bean lifecycle will ease your life significantly (just see how many pitfalls you can avoid). Also note that exceptions thrown from c-tor or #PostContruct method will propagate and cause application context startup to fail as well.
UPDATE: I get your point. This is what came in to my mind:
#Service
public class Singleton {
private static AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();
public Singleton() {
final Singleton previous = INSTANCE.getAndSet(this);
if(previous != null)
throw new IllegalStateException("Second singleton " + this + " created after " + previous);
}
public static Singleton getInstance() {
return INSTANCE.get();
}
}
And let Spring do its job. You can use DI when possible and Singleton.getInstance() where you have to.
Also there are more hard-core solutions like compile-time AspectJ weaving and injecting Spring beans basically to everything.
I'm not sure why you'd want to do this. When you tell Spring that a bean should be a singleton, the corresponding class does not need to be a singleton, and does not need a factory. Spring just simply only ever creates one instance.
The linked article makes no sense to me, since there is NO injection happening, that I can see: "AnyService" is calling the singleton factory method; that the singleton is referenced in the app context is irrelevant until it's referenced, and it seems no other bean references it.
True singleton are hard to get working.
Volatile double-checked locking also does not work property. Read about it on wiki http://en.wikipedia.org/wiki/Double-checked_locking
Your best bet is to simply do this
public class MySingleton {
private static MySingleton INSTANCE = new MySingleton();
That is if you do not have any constructor parameters in your real code.
According to me this is a belts-and-suspenders solution.
If you create a bean and declare it as a singleton in the configuration then there should be no need to protect the bean against being multiply created.
You are now basically protecting yourself from someone wrongly configuring the bean.
I personally would "solve" that by documentation in the spring configuration and Javadoc.
To run code at startup (and fail on error) use one of the many ways to register startup events, e.g. see http://www.baeldung.com/running-setup-logic-on-startup-in-spring
Example:
#Component
public class InitializingBeanExampleBean implements InitializingBean {
private static final Logger LOG = Logger.getLogger(InitializingBeanExampleBean.class);
#Autowired
private Environment environment;
#Override
public void afterPropertiesSet() throws Exception {
LOG.info(Arrays.asList(environment.getDefaultProfiles()));
}
}
#Component
public class SingletonDAOImpl {
}
#Component
public class SingletonDAO {
#Autowired private SingletonDAOImpl instance;
public SingletonDAOImpl getInstance(){
return this.instance
}
}
public class WhateverPlaceYouNeedIt{
#Awtowired private SingletonDAO singletonDao;
public void useSIngleton() {
SingletonDAOImpl INSTANCE = singletonDao.getInstance();
}
}
I tried in so many ways to do something like SingletonDao.instance.doSomething()
but just is not in the spring way and you will find so many hacks in order to do this but is incorrect in my opinion
here
You have your Singleton, which can be changed after in a Multiton
For sure is a single implementation
is respecting the INSTANCE pattern as "getInstance"
Is in-memory so each time is the same object as in singleton
is the same principle applied slightly different, very simple, all the time try to KIS implementation(Keep it simple)