Search code examples
javaspringspring-mvcinversion-of-controlcomponent-scan

Spring Filter components in auto scanning


I have a Spring MVC app. ( an application framework and inversion of control container for the Java platform. The framework's core features can be used by any Java application, but there are extensions for building web applications on top of the Java EE (Enterprise Edition) platform) using this Spring filtering, Now using spring filter

 <context:component-scan base-package="com.pastis"  >
    <context:exclude-filter type="assignable" expression="com.pastis.security.controller.SecurityManagerController"/>
    <context:exclude-filter type="assignable" expression="com.pastis.pq.workflow.web.controller.WorkflowController"/>
    <context:exclude-filter type="regex"      expression="com.pastis.pq.workflow.web.*" />
    <context:exclude-filter type="regex"      expression="com.pastis.security.*" />
    <context:exclude-filter type="regex"      expression="com\.pastis\.security\..*" />
</context:component-scan>

<jpa:repositories base-package="com.pastis.repositories"/>

also tried:

<context:annotation-config />
    <context:component-scan base-package="com.pastis" />
    <context:component-scan base-package="com.pastis.security">
        <context:exclude-filter type="assignable" expression="com.pastis.security.controller.SecurityManagerController"/>
    </context:component-scan>
    <context:component-scan base-package=" com.pastis.pq">
        <context:exclude-filter type="assignable" expression="com.pastis.pq.workflow.web.controller.WorkflowController"/>
        <context:exclude-filter type="assignable" expression="com.pastis.pq.workflow.web.controller.WorkflowAdminController"/>
    </context:component-scan>

but I have a problem with the WorkflowController

and this controller:

com.pastis.security.controller.SecurityManagerController

nevertheless when I start the app. I got this error:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityManagerController':

the servlet-xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:jpa="http://www.springframework.org/schema/data/jpa"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/data/jpa
   http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        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.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- Use annotations to inject stuff -->
    <context:annotation-config />
    <context:component-scan base-package="com.pastis.pq" use-default-filters="false" >
        <context:include-filter type="aspectj" expression="com.pastis.pq.web.endpoint.*" />
        <!--context:include-filter type="annotation" expression="com.pastis.pq.web."-/-->
    </context:component-scan>

    <jpa:repositories base-package="com.pastis.pq.repositories"/>

    <!-- main datasource -->
    <bean id="dataSource"
            class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.h2.Driver" />
        <property name="url" value="jdbc:h2:mem:~/test2;DB_CLOSE_DELAY=-1 />
        <property name="username" value="sa" />
        <property name="password" value="" />
    </bean>

    <!-- transaction management -->
    <tx:annotation-driven/>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <!-- spring data repositories -->
    <jpa:repositories base-package="com.pastis.pq.repositories"/>

    <bean id="jpaVendorAdapter"
              class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">

        <property name="database" value="H2" />
        <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
    </bean>

    <bean id="entityManagerFactory"
              class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="persistenceUnitName" value="pastis-entities" />
        <property name="packagesToScan">
            <array>
              <value>com.pastis.pq.model</value>
            </array>
        </property>
        <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
        <property name="jpaProperties">
            <props>
                <prop key="eclipselink.target-database">org.eclipse.persistence.platform.database.OraclePlatform</prop>
                <prop key="eclipselink.target-server">WebLogic</prop>
            </props>
        </property>
    </bean>

    <!-- customizable database configuration -->
    <bean id="dataConfig" class="com.pastis.commons.services.SystemConfig">
        <constructor-arg index="0" value="test-config.properties"/>
        <constructor-arg index="1" ref="dataSource"/>
    </bean>

 
       
</beans>

the console when I run the tests:

2020-10-08 10:46:57,315 [DEBUG] org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'securityManagerController'
2020-10-08 10:46:57,315 [DEBUG] org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'securityManagerController'
2020-10-08 10:46:57,315 [DEBUG] org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating instance of bean 'securityManagerController'
2020-10-08 10:46:57,315 [DEBUG] org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating instance of bean 'securityManagerController'
2020-10-08 10:46:57,317 [DEBUG] org.springframework.beans.factory.annotation.InjectionMetadata - Registered injected element on class [com.pastis.security.controller.SecurityManagerController]: 

Solution

  • Your initial code snippet is right, but you are not defining the right package for component scanning.

    If the class you want to exclude is this:

    com.pastis.security.controller.SecurityManagerController
    

    Instead of this XML fragment:

    <context:annotation-config />
    <context:component-scan base-package="com.pastis.pq"  >
        <context:exclude-filter type="assignable" expression="com.pastis.security.controller.SecurityManagerController"/>
    </context:component-scan>
    
    <jpa:repositories base-package="com.pastis.pq.repositories"/>
    

    You need something like:

    <context:annotation-config />
    <context:component-scan base-package="com.pastis">
        <context:exclude-filter type="assignable" expression="com.pastis.security.controller.SecurityManagerController"/>
    </context:component-scan>
    
    <jpa:repositories base-package="com.pastis.pq.repositories"/>
    

    Please, notice the change in the package name from com.pastis.pq to com.pastis.

    Or better, define another component-scan element for that purpose:

    <context:annotation-config />
    <context:component-scan base-package="com.pastis.pq" />
    <context:component-scan base-package="com.pastis.security">
        <context:exclude-filter type="assignable" expression="com.pastis.security.controller.SecurityManagerController"/>
    </context:component-scan>
    
    <jpa:repositories base-package="com.pastis.pq.repositories"/>
    

    Please, do not forget to remove the attribute use-default-filters="false"from the <context:component-scan>element. As indicated in the documentation:

    You can also disable the default filters by setting useDefaultFilters=false on the annotation or providing use-default-filters="false" as an attribute of the <component-scan/> element. This will in effect disable automatic detection of classes annotated with @Component, @Repository, @Service, @Controller, or @Configuration.

    This is very likely the reason why in one of the approaches you tried Spring was unable to identify the beans in your com.pastis.pq.web.endpoint.* package.

    As long as you are using <context:component-scan>, probably you can get rid of the <context:annotation-config> element. Please, see this great answer here in stackoverflow.

    UPDATE

    After the different changes in the question, I think that this XML configuration should work properly:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:context="http://www.springframework.org/schema/context"
            xmlns:jpa="http://www.springframework.org/schema/data/jpa"
            xmlns:tx="http://www.springframework.org/schema/tx"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://www.springframework.org/schema/data/jpa
       http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
            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.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd">
    
        <context:component-scan base-package="com.pastis.pq">
            <context:exclude-filter type="assignable" expression="com.pastis.pq.workflow.web.controller.WorkflowController"/>
            <context:exclude-filter type="assignable" expression="com.pastis.pq.workflow.web.controller.WorkflowAdminController"/>
        </context:component-scan>
    
        <context:component-scan base-package="com.pastis.security">
            <context:exclude-filter type="assignable" expression="com.pastis.security.controller.SecurityManagerController"/>
        </context:component-scan>
    
        <jpa:repositories base-package="com.pastis.pq.repositories"/>
    
        <!-- main datasource -->
        <bean id="dataSource"
                class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="org.h2.Driver" />
            <property name="url" value="jdbc:h2:mem:~/test2;DB_CLOSE_DELAY=-1 />
            <property name="username" value="sa" />
            <property name="password" value="" />
        </bean>
    
        <!-- transaction management -->
        <tx:annotation-driven/>
    
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory" />
        </bean>
    
        <!-- spring data repositories -->
        <jpa:repositories base-package="com.pastis.pq.repositories"/>
    
        <bean id="jpaVendorAdapter"
                  class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
    
            <property name="database" value="H2" />
            <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
        </bean>
    
        <bean id="entityManagerFactory"
                  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="persistenceUnitName" value="pastis-entities" />
            <property name="packagesToScan">
                <array>
                  <value>com.pastis.pq.model</value>
                </array>
            </property>
            <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
            <property name="jpaProperties">
                <props>
                    <prop key="eclipselink.target-database">org.eclipse.persistence.platform.database.OraclePlatform</prop>
                    <prop key="eclipselink.target-server">WebLogic</prop>
                </props>
            </property>
        </bean>
    
        <!-- customizable database configuration -->
        <bean id="dataConfig" class="com.pastis.commons.services.SystemConfig">
            <constructor-arg index="0" value="test-config.properties"/>
            <constructor-arg index="1" ref="dataSource"/>
        </bean>
    
    </beans>