context:component- scan
context:component- scan element helps to identify the java classes which can be registered as a spring beans.
Let us understand how context:component- scan works ?
step 1
All the java classes that need to register as a spring bean must be annotated with at least one of the below annotation
a) @Component
b) @Controller
c) @Repository
d) @Service
e) Any custom annotation that itself has annotated with one of the above annotation
Step 2
context:component- scan element must have the base-package attribute whose value should be the package name where all the java classes which have any one of the above 5 annotation are defined.
So if we want to make the java class as a spring bean then these 2 steps should be followed
Step 1
Annotate your class with any one of the above annotation
Step 2
Add the package where your java class is available into base-package value.
Lets see the Example below
Create Person.java
- package com.kb.componentscan;
- import org.springframework.stereotype.Component;
- @Component
- public class Person {
- public Person() {
- System.out.println("person");
- }
- }
package com.kb.componentscan; import org.springframework.stereotype.Component; @Component public class Person { public Person() { System.out.println("person"); } }
Create Car.java
- package com.kb.componentscan;
- import org.springframework.stereotype.Component;
- @Component
- public class Car {
- }
package com.kb.componentscan; import org.springframework.stereotype.Component; @Component public class Car { }
Create beans.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <context:component-scan base-package="com.kb.componentscan" />
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.kb.componentscan" /> </beans>
Look at both the classes are annotated with @Component and both the classes are in the same package com.kb.componentscan and this package is included inside context:component-scan.
So now both the classes are considered as spring beans.
The above beans.xml is same as below
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <bean id="person" class= "com.kb.componentscan.Person"/>
- <bean id="car" class= "com.kb.componentscan.Car"/>
- </beans>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="person" class= "com.kb.componentscan.Person"/> <bean id="car" class= "com.kb.componentscan.Car"/> </beans>
Create MainClient.java
- package com.kb.componentscan;
- import org.springframework.beans.BeansException;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class MainClient {
- public static void main(String[] args) {
- ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/kb/componentscan/beans.xml");
- Person person= (Person)applicationContext.getBean("person");
- System.out.println("end");
- }
- }
package com.kb.componentscan; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainClient { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/kb/componentscan/beans.xml"); Person person= (Person)applicationContext.getBean("person"); System.out.println("end"); } }
Output
Context:component-scan – filtering
Assume inside a package com.kb, we have 2 sub packages service and DAO
I want all classes comes under both the package service and DAO to register as a spring bean,even though they are not annotated with any of the stereotype annotation then I cannot achieve it with just context:component-scan,but if we use filtering we can achieve it easily
Filter types are
1) context:include-filter – it suggests context:component-scan what needs to be registered as a spring bean.
2) context:exclude-filter – it suggest context:component-scan what not to be registered as a spring bean.
Context:include-filter and Context:exclude-filter have 2 attributes
1) type -> Spring supports 5 types of Filter expression and they are
annotation: specify an annotation type for filtering.
assignable: specify a class/interface for filtering.
aspectj: specify an AspectJ pointcut expression for matching the classes.
regex: specify a regular expression for matching the classes.
custom: A custom implementation of the org.springframework.core.type.TypeFilter interface.
2) expression – specifies the expression to consider and evaluate based on filter type.
Let’s see with the regex example as below
Package Hierarchy is given below
Now I want to register those classes which comes under sub-packages of componentscan-filters even though they are not annotated.
LoginDAO.java
- package com.kb.componentscan_filters.DAO;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
- import com.kb.componentscan_filters.service.LoginService;
- public class LoginDAO {
- @Autowired
- LoginService loginService;
- public void hello(){
- System.out.println("hello");
- }
- }
package com.kb.componentscan_filters.DAO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.kb.componentscan_filters.service.LoginService; public class LoginDAO { @Autowired LoginService loginService; public void hello(){ System.out.println("hello"); } }
LoginService.java
- package com.kb.componentscan_filters.service;
- public class LoginService {
- }
package com.kb.componentscan_filters.service; public class LoginService { }
beans.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <context:component-scan base-package="com.kb.componentscan_filters">
- <context:include-filter type="regex" expression="com.kb.componetscan_filters.service.*"/>
- <context:include-filter type="regex" expression="com.kb.componetscan_filters.DAO.*"/>
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.kb.componentscan_filters"> <context:include-filter type="regex" expression="com.kb.componetscan_filters.service.*"/> <context:include-filter type="regex" expression="com.kb.componetscan_filters.DAO.*"/> </beans>
MainClient.java
- package com.kb.componentscan_filters;
- import org.springframework.beans.BeansException;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import com.kb.componentscan_filters.DAO.LoginDAO;
- public class MainClient {
- public static void main(String[] args) {
- ApplicationContext applicationContext = new
- ClassPathXmlApplicationContext("com/kb/componentscan_filters/beans.xml");
- LoginDAO loginDAO = (LoginDAO)applicationContext.getBean("loginDAO");
- loginDAO.hello();
- System.out.println("end");
- }
- }
package com.kb.componentscan_filters; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.kb.componentscan_filters.DAO.LoginDAO; public class MainClient { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/kb/componentscan_filters/beans.xml"); LoginDAO loginDAO = (LoginDAO)applicationContext.getBean("loginDAO"); loginDAO.hello(); System.out.println("end"); } }
Output
Include vs Exclude Filter priority
Package Hierarchy is given below
- package com.kb.componentscan_filters.DAO;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
- import com.kb.componentscan_filters.service.LoginService;
- public class LoginDAO {
- @Autowired
- LoginService loginService;
- public void hello(){
- System.out.println("hello");
- }
- }
package com.kb.componentscan_filters.DAO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.kb.componentscan_filters.service.LoginService; public class LoginDAO { @Autowired LoginService loginService; public void hello(){ System.out.println("hello"); } }
LoginService.java
- package com.kb.componentscan_filters.service;
- public class LoginService {
- }
package com.kb.componentscan_filters.service; public class LoginService { }
beans.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <context:component-scan base-package="com.kb.componentscan_filters">
- <context:exclude-filter type="regex" expression=".*service.*"/>
- <context:exclude-filter type="regex" expression=".*DAO.*"/>
- <context:include-filter type="regex" expression.*service.*"/>
- <context:include-filter type="regex" expression=".*DAO.*"/>
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.kb.componentscan_filters"> <context:exclude-filter type="regex" expression=".*service.*"/> <context:exclude-filter type="regex" expression=".*DAO.*"/> <context:include-filter type="regex" expression.*service.*"/> <context:include-filter type="regex" expression=".*DAO.*"/> </beans>
MainClient.java
- package com.kb.componentscan_filters;
- import org.springframework.beans.BeansException;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import com.kb.componentscan_filters.DAO.LoginDAO;
- public class MainClient {
- static ApplicationContext applicationContext ;
- public static void main(String[] args) {
- ApplicationContext applicationContext = new
- ClassPathXmlApplicationContext("com/kb/componentscan_filters/beans.xml");
- LoginDAO loginDAO = (LoginDAO)applicationContext.getBean("loginDAO");
- loginDAO.hello();
- System.out.println("end");
- }
- }
package com.kb.componentscan_filters; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.kb.componentscan_filters.DAO.LoginDAO; public class MainClient { static ApplicationContext applicationContext ; public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/kb/componentscan_filters/beans.xml"); LoginDAO loginDAO = (LoginDAO)applicationContext.getBean("loginDAO"); loginDAO.hello(); System.out.println("end"); } }
Output
It means first filter inside xml must be include always.
If we put exclude first then we will end up with the above exception.
Now Reverse the order – place include first and then exclude
beans.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <context:component-scan base-package="com.kb.componentscan_filters">
- <context:include-filter type="regex" expression.*service.*"/>
- <context:include-filter type="regex" expression=".*DAO.*"/>
- <context:exclude-filter type="regex" expression=".*service.*"/>
- <context:exclude-filter type="regex" expression=".*DAO.*"/>
- </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.kb.componentscan_filters"> <context:include-filter type="regex" expression.*service.*"/> <context:include-filter type="regex" expression=".*DAO.*"/> <context:exclude-filter type="regex" expression=".*service.*"/> <context:exclude-filter type="regex" expression=".*DAO.*"/> </beans>
Run above MainClient.java
Output
This is because include filter is trying to take the beans registration but exclude filter overrides the same and exclude those beans from the registration.
Hence no bean is registered and hence the exception above is appearing.
Thanx! This helped..
not clear
great article