What in the World Are Spring Beans

What in the world are Spring beans?

The Spring core technologies reference documentation describes what beans are.

Per the Introduction to the Spring IoC Container and Beans section (where "IoC" means "inversion of control"):

In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.

Beans and scope are described in the Bean Scopes section:

When you create a bean definition, you create a recipe for creating actual instances of the class defined by that bean definition. The idea that a bean definition is a recipe is important, because it means that, as with a class, you can create many object instances from a single recipe.

You can control not only the various dependencies and configuration values that are to be plugged into an object that is created from a particular bean definition but also control the scope of the objects created from a particular bean definition. This approach is powerful and flexible, because you can choose the scope of the objects you create through configuration instead of having to bake in the scope of an object at the Java class level. Beans can be defined to be deployed in one of a number of scopes.

Whats bean in spring and what is not

In the context of Spring, A bean is a spring managed object. Here spring managed means an object created, initialised, managed, destroyed by Spring IoC container.

Whenever we mark a class with @Component, Spring IOC container will create object for your class and manage it, Whenever we can simply get it from ApplicationContext, or access it using @Autowired/@Resource/@Inject annotations

We can also use @Controller, @Repository, @Service, @ControllerAdvice, @Configuration,@Aspect in place of @Component to tell more specifically that our class is a service or a repository or an aspect etc.

We can also use @Bean annotation to create a bean from method return value

@Configuration
public class SolrConfig {

@Value("${spring.data.solr.host}") String solrUrl;

@Bean
public SolrServer solrServer() {
return new HttpSolrServer(solrUrl);
}

@Bean(name = "solrTemplate")
public SolrTemplate solrTemplate() {
return new SolrTemplate(new HttpSolrServer(solrUrl), RULE_ENGINE_CORE);
}
}

Use/Purpose of beans in Spring

I understand the standard Java bean (no arg constructor,
getters/setters, often serialized), but the Spring bean purpose seems
to be different.

You mean always serialized. Why do you think the purpose seems different?

In the end, you write classes. A lot of time these are POJOs, Plain Old Java Objects. Sometimes you implement an interface or extend a class, but its all just classes.

Beans are just classes. Don't overcomplicate it.

Now Spring might take your beans (classes) and manage them for you via any of a number of policies (prototype, singleton) but that doesn't change what a bean is, it speaks to how Spring manages the bean.

Changing the Spring beans implementation at runtime

It doesn't work this way - if you have a certain implementation of Util wired to, say, class SampleClass (which is a singleton) you can't really change the implementation of the Util to something different without restarting the application context.

So instead of going this way, I suggest an alternative. You say that under certain conditions that evaluate in runtime you want to switch implementations. What kind of condition it is? Is it possible to extract this condition decision logic?

If so, you can autowire a special DynamicUtil that will hold the reference to all the utils and will call the required util depending on the condition:

// represents all possible business 'runtime' outcomes
enum ConditionOutcome {
A, B, C
}
interface ConditionEvaluator {
ConditionOutcome evaluate(); // when called in runtime will evaluate a condition that currently exists in the system
}

interface Util {
void foo();
ConditionOutcome relevantOfOutcome();
}

class Utill1Impl implements Util {
public void foo() {...}
public ConditionOutcome relevantOfOutcome() {return ConditionOutcome.A;}
}
class Utill2Impl implements Util {
public void foo() {...}
public ConditionOutcome relevantOfOutcome() {return ConditionOutcome.B;}
}
class Utill3Impl implements Util {
public void foo() {...}
public ConditionOutcome relevantOfOutcome() {return ConditionOutcome.C;}
}

class DynamicUtil {
private final Map<ConditionOutcome, Util> possibleImpls;
private final ConditionEvaluator evaluator;

public class DynamicUtil(List<Util> allImplementations, ConditionEvaluator evaluator) {
// create a map by calling the 'relevantOfOutcome' per util impl in a loop
this.evaluator = evaluator;
}

public void foo() {
ConditionOutcome key = evaluator.evaluate();
// pick the relevant implementation based on evaluated key
possibleImpls.get(key).foo();
}
}

Now with such a design you can dynamically add new possible outcomes (along with utils that should implement them. You classes in the system will have to autowire DynamicUtil though, so effectively you'll introduce one additional level of indirection but will gain flexibility

class SampleClass { // a business class that will need to work with util capable of being changed during the runtime 
@Autowired
private DynamicUtil util;
...
}


Related Topics



Leave a reply



Submit