Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring: Properly setup @ComponentScan

I have following set up for my Spring Application Context.


@Configuration
public class RmiContext {
@Bean
    public RmiProxyFactoryBean service() {
        RmiProxyFactoryBean rmiProxy = new RmiProxyFactoryBean();
        rmiProxy.setServiceUrl("rmi://127.0.1.1:1099/Service");
        rmiProxy.setServiceInterface(Service.class);
        return rmiProxy;
    }
}


@Configuration
public class LocalContext {
@Bean
    public Controller Controller() {
        return new ControllerImpl();
    }
}


@Configuration
@Import({RmiContext.class, LocalContext.class})
public class MainContext {

}

The above setup works fine, but I want to enable @ComponentScan annotating Controllers with @Component as there are many Controllers in my application which is tedious when declared one by one using @Bean.


@Configuration
@ComponentScan(basePackageClasses = {Controller.class})
public class LocalContext {
    /* ... */
}
The problem is that when I do @ComponentScan(basePackageClasses = {Controller.class}), the previously fine working RmiProxyFactoryBean are not recognized or can't be created.

So, How do I configure my MainContext so that both beans via RMI and local beans are created?

like image 257
TheKojuEffect Avatar asked Jul 25 '13 12:07

TheKojuEffect


People also ask

What does @ComponentScan do in Spring?

One of the most important annotations in spring is @ComponentScan which is used along with the @Configuration annotation to specify the packages that we want to be scanned. @ComponentScan without arguments tells Spring to scan the current package and all of its sub-packages.

What is @configuration @EnableAutoConfiguration and ComponentScan?

@EnableAutoConfiguration : enable Spring Boot's auto-configuration mechanism. @ComponentScan : enable @Component scan on the package where the application is located (see the best practices) @Configuration : allow to register extra beans in the context or import additional configuration classes.

Which of the following is best practices of using @ComponentScan annotation in Spring?

A good practice is to explicitly import a @Configuration class with the @Import annotation and add the @ComponentScan annotation to that configuration class to auto-scan only the package of that class. This way, we have clean boundaries between the packages of our application.

Can we use @ComponentScan without @configuration?

@Configuration is meta annotated with @Component , which marks it eligible for classpath scanning. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig. class); @Bean doesn't need @ComponentScan as all these beans are created explicitly when spring encounters this annotation.


2 Answers

@Configuration is also a candidate for component scan, so you can scan all the beans in RmiContext and all controllers in your controller package by:

@Configuration
@ComponentScan(basePackages = {"org.example.controllers", "package.of.RmiContext"})
public class MainContext {
}

--edit--

@Configuration is a candidate for component scan, here is the test case that works in my pc:

package scan.controllers;
@Controller
public class ExampleController {
}

package scan;
public interface RMIService {
}

package scan;
@Configuration
public class RmiContext {
    @Bean
    public RmiProxyFactoryBean service() {
        RmiProxyFactoryBean rmiProxy = new RmiProxyFactoryBean();
        rmiProxy.setServiceUrl("rmi://127.0.1.1:1099/Service");
        rmiProxy.setServiceInterface(RMIService.class);
        rmiProxy.setLookupStubOnStartup(false);
        return rmiProxy;
    }
}

package scan;
@Configuration
//MainContext will auto scan RmiContext in package scan and all controllers in package scan.controllers
@ComponentScan(basePackages = {"scan", "scan.controllers"})
public class MainContext {
}

package scan;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={MainContext.class})
public class TestContext {

    @Autowired private RMIService rmi;
    @Autowired private ExampleController controller;

    @Test
    public void test() {
        //both controller and rmi service are autowired as expected
        assertNotNull(controller);
        assertNotNull(rmi);
    }
}
like image 147
Septem Avatar answered Sep 18 '22 08:09

Septem


May be you could try using the base packages of your classes (RMI, Controller):


@ComponentScan(basePackages = {"your controller package", "your rmi package"})

If the RMI classes package is different than controller then they will fail to instantiate by spring.

like image 43
Shamim Ahmmed Avatar answered Sep 22 '22 08:09

Shamim Ahmmed