Magic behind #ComponentScan and #Component - java

I'm still learning spring dependency injection in depth.
My first class is a configuration class, where i declare to the container to load and manage the beans declared in the annotated methods.
package ioc.question_004;
import ioc.commun.Person;
import ioc.commun.Profession;
import org.springframework.context.annotation.*;
#Configuration
public class MyConfiguration {
#Bean
public Profession profession(){
return Profession.builder()
.name("professor")
.description("professor in the university")
.build();
}
#Bean
public Person person(){
return Person.builder()
.name("Bagna")
.age(52)
.profession(profession())
.build();
}
}
My second class is a daoRepository, it looks likes:
package ioc.question_008.dao;
import ioc.commun.Person;
import lombok.*;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
#Repository
#Builder
#Setter
#Getter
#EqualsAndHashCode
#ToString
public class MyDaoRepository implements dao {
List<Person> personList = new ArrayList<>();
#Override
public boolean save( Person person ){
return this.personList.add(person);
}
#Override
public boolean delete( Person person ){
return this.personList.remove(person);
}
}
My running code is as follows:
#Configuration
#Import(MyConfiguration.class)
#ComponentScan(basePackageClasses = {MyDaoRepository.class} )
public class DependencyInjection {
public static void main( String[] args ) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DependencyInjection.class);
dao myDaoRepository = (MyDaoRepository) context.getBean("myDaoRepository");
System.out.println(myDaoRepository);
}
}
Magically MyDaoRepository contains the #Bean person declared in the configuration class MyConfiguration:
MyDaoRepository(personList=[Person(name=Bagna, age=52, profession=Profession(name=professor,
description=professor in the university))])
I thnik that the container injected this object automatically even if i didn't ask for that. May be some #Autowired annotation is added by the compiler. I'm not sure.
Could you please explain to me how i can ask the spring container to not inject the beans even if they exists in the container(the bean person for example), unless i ask the to do the injection by myself with the #Autowired annotation.

The reason is the combination of spring's autowiring of collections and lombok's Builder
First, the #Builder adds an all args constructor MyDaoRepository(List<Person> list).
Second, spring automatically detects your factory methods #Bean public Person person().
Now, since the constructor expects a collection, spring accumulates all Person-beans it can find into a List and injects it into the constructor, setting the list accordingly.
I think (but it is currently untested but documented here), that adding #Autowired(required = false) to your List<Person> persons property is what you want in this case, as that marks it as optional and spring will not inject it. (EDIT: I was mistaken, you still need the no-args-constructor for this to work, but without any #Autowired annotation the list would not get injected that way anyway. The required=false simply prevents the exception when no proper Person bean is found.)
EDIT: As Mr. Roddy, the Roddy of the Frozen Peas, pointed out, it would also be possible to add a different constructor for spring to create your bean, e.g. by annotating your repository with #NoArgsConstructor

Related

Spring Boot defining bean in configuration problem

I'm working on a project on my sparetime, on this project I have been asked to work with Spring Boot. I'm not familiar with Spring Boot from before, and I have tried searching here on stackoverflow and Google, but I can't seem to understand how the different solutions for my problem works.
First of all, this is my error message:
Parameter 0 of constructor in com.project.example.controller.VerverController required a bean of type 'com.project.example.dao.VerverDao' that could not be found.
Action:
Consider defining a bean of type 'com.project.example.dao.VerverDao' in your configuration.
After some reading, I understood that this could be because of Spring Boot don't scan this class / interface. So I tried to add ComponentScan, with no luck.
I tried to convert VerverDao from interface to class and register a bean with bean annotation. Still no luck. I tried to move the VerverDao from the dao package to the root package (the same as the Main class) and still no luck.
So if someone could please help me understand the error message, it would make my day.
This is my structure:
This is my code:
Probably some of the annotation is wrong as well, since I'm not used to Spring Boot, in advance thanks for correcting me on the use of these
It is also worth mentioning that I'm using Lombok as well on this project.
Main.java
#ComponentScan("com.gambinomafia")
#SpringBootApplication
public class Main extends SpringBootServletInitializer {
public static void main(String[] args) {
new Main().configure(new SpringApplicationBuilder(Main.class)).run(args);
}
}
Configuration.java
#Component
public class Configuration extends ResourceConfig {
public Configuration() {
register(VerverResourceImpl.class, VerverResource.class);
register(VerverController.class);
register(VerverDao.class);
}
}
VerverResource.java
#Resource
#Path("verver")
public interface VerverResource {
#GET
#Path("/{userid}")
#Produces(MediaType.APPLICATION_JSON)
String getRefferingUrl(#PathParam("userid") int userid);
}
VerverResourceImpl.java
#AllArgsConstructor(onConstructor = #__({#Inject}))
public class VerverResourceImpl implements VerverResource {
private VerverController controller;
#Override
public String getRefferingUrl(int userid) {
log.info("Collection reciever url for user id: {}", userid);
return controller.getRefferingUrl(userid);
}
}
VerverController.java
#Controller
#AllArgsConstructor
public class VerverController {
private VerverDao ververDao;
public String getRefferingUrl(int userid) {
User user = ververDao.getUsername(userid);
if (user.getUsername().isEmpty()) {
throw new NotFoundException("Did not find any user with id " + userid);
}
return "<url-to-site>/?verv=" + user.getUsername();
}
}
VerverDao.java
#AllArgsConstructor
public class VerverDao {
#Value("spring.datasource.url")
private String dbcon;
public User getUsername(int userid) {
Jdbi jdbi = Jdbi.create(dbcon);
return jdbi.withHandle(handle -> handle.createQuery(
"SELECT id, brukernavn FROM t_user WHERE id = :id")
.bind("id", userid)
.mapToBean(User.class)
.findOnly());
}
}
Feel free to ask for more information, if there is missing some information in the topic. I will try to answer as fast as possible.
First at all, you're setting a #ComponentScan with a wrong package in your Application class.
#ComponentScan("com.gambinomafia")
#SpringBootApplication
And, according to the picture, it has to be:
#ComponentScan("com.project.example")
#SpringBootApplication
EDIT: the use of #ComponentScan by #M.Deinum
Because of the Application Class is in the root package and #SpringBootApplication already contains #ComponentScan, It isn't needed to declare #ComponentScan.
Second, instead of use a DAO you can use Repositories. There is more information here: Spring Boot Repositories.
Third, to inject your objects you can use #Autowired over the constructor.
#Controller
public class VerverController
private VerverDao ververDao;
#Autowired
public VerverController(VerverDao ververDao) {
this.ververDao = ververDao;
}
}
There is more information here.
Log clearly says
VerverController required a bean of type 'com.project.example.dao.VerverDao' that could not be found.
It means there is no bean of type com.project.example.dao.VerverDao
Add #Repository on top of VerverDao to resolve the issue.
#Repository
#AllArgsConstructor
public class VerverDao {
}
Note: Ensure VerverDao is in component scanning path as per your package structure.

BeanNotOfRequiredTypeException: Bean named X is expected to be of type X but was actually of type 'com.sun.proxy.$Proxy

I have such classes and Spring context.
How to fix this wrong Java configuration, not xml?
I'd tried some solutions from other posts, but without success.
#Service
#Transactional
public class XCalculationService implements VoidService<X> {
}
public interface VoidService<Input> {
}
#AllArgsConstructor
public class XService {
private XCalculationService calculationService;
}
#Configuration
public class ServiceConfiguration {
#Bean
public OrderService orderService(XCalculationService calculationService) {
return new XService(calculationService);
}
#Bean
public XCalculationService calculationService() {
return new XCalculationService ();
}
}
Error
BeanNotOfRequiredTypeException: Bean named 'calculationService' is expected to be of type 'com.x.XCalculationService' but was actually of type 'com.sun.proxy.$Proxy
Here is 100% fix:
#EnableTransactionManagement(proxyTargetClass = true)
Java proxies are working on interfaces, not concrete classes.
Reasoning with spring documentation: https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch08s06.html
If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used.
Therefore, when using aspect/proxy based annotations as #Transactional, Spring will attempt to proxify the concrete class and resulting object will be instance of VoidService interface not XCalculationService.
Therefore you can solve it two ways:
use #Arthur solution and turn off Java's interface proxy in favor of CGLib for transaction support
#EnableTransactionManagement(proxyTargetClass = true)
Instead of using XCalculationService type in injectable fields, use only its proxied interface aka VoidService.
I suppose you have got #ComponentScan somewhere activated and it scans your #Service annotated XCalculationService class.
So you should either remove #Service from XCalculationService
or remove
#Bean
public XCalculationService calculationService() {
return new XCalculationService ();
}
from ServiceConfiguration

Behaviour of lite #Bean methods in Spring 5

From the Spring 5 docs
When #Bean methods are declared within classes that are not annotated
with #Configuration they are referred to as being processed in a
'lite' mode. Bean methods declared in a #Component or even in a plain
old class will be considered 'lite', with a different primary purpose
of the containing class and an #Bean method just being a sort of bonus
there. For example, service components may expose management views to
the container through an additional #Bean method on each applicable
component class. In such scenarios, #Bean methods are a simple
general-purpose factory method mechanism.
Unlike full #Configuration, lite #Bean methods cannot declare
inter-bean dependencies. Instead, they operate on their containing
component’s internal state and optionally on arguments that they may
declare. Such an #Bean method should therefore not invoke other #Bean
methods; each such method is literally just a factory method for a
particular bean reference, without any special runtime semantics. The
positive side-effect here is that no CGLIB subclassing has to be
applied at runtime, so there are no limitations in terms of class
design (i.e. the containing class may nevertheless be final etc).
The #Bean methods in a regular Spring component are processed
differently than their counterparts inside a Spring #Configuration
class. The difference is that #Component classes are not enhanced with
CGLIB to intercept the invocation of methods and fields. CGLIB
proxying is the means by which invoking methods or fields within #Bean
methods in #Configuration classes creates bean metadata references to
collaborating objects; such methods are not invoked with normal Java
semantics but rather go through the container in order to provide the
usual lifecycle management and proxying of Spring beans even when
referring to other beans via programmatic calls to #Bean methods. In
contrast, invoking a method or field in an #Bean method within a plain
#Component class has standard Java semantics, with no special CGLIB
processing or other constraints applying.
I would have expected that the following code throws an exception / bean1.bean2 to be null and that the init method would not be executed. However, the code below runs fine and prints:
Should never be invoked
Expected null but is ch.litebeans.Bean2#402bba4f
So for me it looks like lite beans behave the same as beans constructed from an #Configuration annotated class. Can someone point out in which scenario this is not the case?
.
package ch.litebeans;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class);
Bean1 bean1 = ctx.getBean(Bean1.class);
System.out.println("Expected null but is " + bean1.getBean2());
}
}
package ch.litebeans;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = {"ch.litebeans"})
public class ApplicationConfig {}
package ch.litebeans;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
#Component
public class Factory1 {
#Bean
public Bean1 getBean1(Bean2 bean2){
return new Bean1(bean2);
}
}
package ch.litebeans;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
#Component
public class Factory2 {
#Bean(initMethod = "init")
public Bean2 getBean2(){
return new Bean2();
}
}
package ch.litebeans;
public class Bean1 {
private Bean2 bean2;
public Bean1(Bean2 bean2){
this.bean2 = bean2;
}
public Bean2 getBean2(){
return bean2;
}
}
package ch.litebeans;
public class Bean2 {
public void init(){
System.out.println("Should never be invoked");
}
}
EDIT:
Based on the explanation of Mike Hill I added an example demonstrating the difference:
public class BeanLiteRunner {
public static void main(String[] args) {
AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(MyComponent.class,
MyConfiguration.class);
MyComponent.MyComponentBean1 componentBean1 = acac.getBean(MyComponent.MyComponentBean1.class);
MyComponent.MyComponentBean1 componentBean2 = acac.getBean(MyComponent.MyComponentBean1.class);
MyConfiguration.MyConfigurationBean1 configurationBean1 = acac.getBean(MyConfiguration
.MyConfigurationBean1.class);
MyConfiguration.MyConfigurationBean1 configurationBean2 = acac.getBean(MyConfiguration
.MyConfigurationBean1.class);
}
}
#Component
public class MyComponent {
#Bean
public MyComponent.MyComponentBean1 getMyComponentBean1(){
return new MyComponent.MyComponentBean1(getMyComponentBean2());
}
#Bean
public MyComponent.MyComponentBean2 getMyComponentBean2(){
return new MyComponent.MyComponentBean2();
}
public static class MyComponentBean1{
public MyComponentBean1(MyComponent.MyComponentBean2 myComponentBean2){
}
}
public static class MyComponentBean2{
public MyComponentBean2(){
System.out.println("Creating MyComponentBean2");
}
}
}
#Configuration
public class MyConfiguration {
#Bean
public MyConfigurationBean1 getMyConfigurationBean1(){
return new MyConfigurationBean1(getMyConfigrationBean2());
}
#Bean
public MyConfigurationBean2 getMyConfigrationBean2(){
return new MyConfigurationBean2();
}
public static class MyConfigurationBean1{
public MyConfigurationBean1(MyConfigurationBean2 myConfigurationBean2){}
}
public static class MyConfigurationBean2{
public MyConfigurationBean2(){
System.out.println("Creating MyConfigrationBean2");
}
}
}
The output is as expected
> Creating MyComponentBean2
> Creating MyComponentBean2
> Creating MyConfigrationBean2
This is not a bug. Spring's lite bean definitions are automatically added to the context during the component scan. Bean definitions using a factory method (i.e., all #Bean-defined beans) will automatically attempt to autowire parameters using the current context. See ConstructorResolver#instantiateUsingFactoryMethod for more details.
The referenced documentation is perhaps not entirely clear. The primary differentiation between "lite" and "full" bean configurations is strictly the proxying that is done in "full" (#Configuration) mode. Take for example what would happen if we instead defined our beans in a #Configuration class:
#Configuration
public MyConfiguration {
#Bean
public Bean1 bean1() {
return new Bean1(bean2());
}
#Bean
public Bean2 bean2() {
return new Bean2();
}
}
The call to bean2() from within bean1() will actually reference the singleton bean2 instance from the context rather than directly calling the bean2() method as implemented. In fact, it doesn't matter how many bean2() method calls are made from within that configuration class -- the real bean2 method will only be executed one time.
"Lite"-mode does not proxy these methods, meaning that each bean2() method call will actually directly reference the method implementation and will not return the bean that is in the context. Rather, it will create a new separate instance that is not tracked by the context (as is the default Java behavior).

Spring annotations confusion

i am really confused with spring annotations.
where to use # Autowired, where class is # Bean or # Component,
i understand we cannot use
Example example=new Example("String");
in Spring
but how alone
#Autowired
Example example;
will solve the purpose?
what about Example Constructor ,how spring will provide String value to Example Constructor?
i went through one of the article but it does not make much sense to me.
it would be great if some one can give me just brief and simple explanation.
Spring doesn't say you can't do Example example = new Example("String"); That is still perfectly legal if Example does not need to be a singleton bean. Where #Autowired and #Bean come into play is when you want to instantiate a class as a singleton. In Spring, any bean you annotate with #Service, #Component or #Repository would get automatically registered as a singleton bean as long as your component scanning is setup correctly. The option of using #Bean allows you to define these singletons without annotating the classes explicitly. Instead you would create a class, annotate it with #Configuration and within that class, define one or more #Bean definitions.
So instead of
#Component
public class MyService {
public MyService() {}
}
You could have
public class MyService {
public MyService() {}
}
#Configuration
public class Application {
#Bean
public MyService myService() {
return new MyService();
}
#Autowired
#Bean
public MyOtherService myOtherService(MyService myService) {
return new MyOtherService();
}
}
The trade-off is having your beans defined in one place vs annotating individual classes. I typically use both depending on what I need.
You will first define a bean of type example:
<beans>
<bean name="example" class="Example">
<constructor-arg value="String">
</bean>
</beans>
or in Java code as:
#Bean
public Example example() {
return new Example("String");
}
Now when you use #Autowired the spring container will inject the bean created above into the parent bean.
Default constructor + #Component - Annotation is enough to get #Autowired work:
#Component
public class Example {
public Example(){
this.str = "string";
}
}
You should never instantiate a concrete implementation via #Bean declaration. Always do something like this:
public interface MyApiInterface{
void doSomeOperation();
}
#Component
public class MyApiV1 implements MyApiInterface {
public void doSomeOperation() {...}
}
And now you can use it in your code:
#Autowired
private MyApiInterface _api; // spring will AUTOmaticaly find the implementation

Javaconfig bean overriding failing with List injected

I consider injection of beans as a List of automatically detected beans: I introduce several beans implementing the same interface and inject all of them as a List in a later bean.
I've not been able to find official documentation related to this feature. My single source is http://www.coderanch.com/t/605509/Spring/Java-config-autowired-List
Considering this feature, I have an issue with Bean overring: I would like to override a bean defined throught a no-arg method with a bean defined with the List of detected beans. However, spring behave like the second bean definition does not exist.
It can be reproduced with the following test:
import java.util.Date;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class SpringTest {
#Test
public void shouldtestSpringDifferentMethodNames() {
AnnotationConfigApplicationContext ctx2 = new AnnotationConfigApplicationContext(AConfig.class, CConfig.class);
Assert.assertEquals("overriden", ctx2.getBean("bean"));
}
#Configuration
public static class AConfig {
#Bean
public Object bean() {
return "not overriden";
}
}
#Configuration
public static class CConfig extends AConfig {
#Bean
public Date anotherBean() {
return new Date();
}
#Bean
public Object bean(List<? extends Date> someDate) {
return "overriden";
}
}
}
If this is an expected behavior, how can I achieve such an overriding?
documentation for list autowire can be found at spring documentation
overriding of beans by id or name is not official spring feature - look for that question for more details
This has been considered as a bug by the Spring team: https://jira.springsource.org/browse/SPR-10988
A recent piece of documentation can be found at: http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-autowired-annotation (Thanks Alexander Kudrevatykh for the 2.5 source)

Categories