Customizing Broadleaf Beans
Overrides
Broadleaf comes with hundreds of Spring components, all of which can be overridden or customized in one way or another. A simple but common example is to override CustomerService
and change which implementation that gets created depending on something about the request.
If we look for implementations of the CustomerService
interface we see CustomerServiceImpl
. This is annotated with @Service("blCustomerService")
(as almost all Broadleaf beans start with bl
), which means that we need to create an override for the blCustomerService
bean. We start with creating a subclass of CustomerServiceImpl
:
package com.mycompany;
public class MyCustomerService extends CustomerServiceImpl {
@Override
public Customer createCustomer() {
if (RequestContextHolder.getRequestAttributes().getAttribute("someSessionAttribute", SCOPE_SESSION)) {
MyCustomer customer = new MyCustomer();
customer.setId(findNextCustomerId());
}
}
}
This assumes that you have already added
MyCustomer
as an entity outlined in Creating a New Entity
@Component/@Service/@Repository
are intentionally left off of this class to exclude it from regular component scanning
Java Configuration
Create an @Configuration
class within the package org.broadleafoverrides.config
that contains an @Bean
method that returns your override. The method name must be the exact same as the bean name:
package org.broadleafoverrides.config;
@Configuration
public class BroadleafOverrides {
@Bean
public CustomerService blCustomerService() {
return new MyCustomerService();
}
}
XML
One way to guarantee your override is to add an @ImportResource
to an XML file that contains the following:
<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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="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">
<bean id="blCustomerService" class="com.mycompany.MyCustomerService />
</beans>
Then we create a special @Configuration
clas
By looking through the INFO-level logging on org.springframework
, on startup you should see the following log message:
2017-06-14 10:55:58.287 INFO 10427 --- [ost-startStop-1] o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition for bean 'blCustomerService' with a different definition: replacing [Generic bean: class [org.broadleafcommerce.profile.core.service.CustomerServiceImpl]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in URL [jar:file://apache-tomcat-7.0.78/webapps/site/WEB-INF/lib/broadleaf-profile-5.2.0-SNAPSHOT.jar!/org/broadleafcommerce/profile/core/service/CustomerServiceImpl.java.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=broadleafOverrides; factoryMethodName=blCustomerService; initMethodName=null; destroyMethodName=(inferred); defined in com.mycompany.MyCustomerService]]
This log message will be slightly different depending on if you overwrote the bean with XML or Java
@Configuration
Java @Configuration
package scanning
In order for bean overrides to work, Broadleaf scans various packages looking for @Configuration
classes in different contexts, depending on which @EnableBroadleaf...
annotation you have active. Doing a search in your project indicates which annotations you have active.
Annotation Used | Bean Override Packages Scanned | Used When... |
---|---|---|
@EnableBroadleafSiteAutoConfiguration |
org.broadleafoverrides.config , org.broadleafoverrides.site.config |
There is a single ApplicationContext , only in the site project. This is the default for fresh Broadleaf 5.2+ projects |
@EnableBroadleafSiteRootAutoConfiguration |
org.broadleafoverrides.config , org.broadleafoverrides.site.config |
There are multiple ApplicationContext s and the override is only for beans in the root (the majority of the Broadleaf beans) only in the site project. Default for projects upgraded to Broadleaf 5.2 |
@EnableBroadleafSiteServletAutoConfiguration |
org.broadleafoverrides.servlet.config , org.broadleafoverrides.site.servlet.config |
There are multiple ApplicationContext s and the override is only for beans in the servlet only in the site project. Default for projects upgraded to Broadleaf 5.2 |
@EnableBroadleafAdminAutoConfiguration |
org.broadleafoverrides.config , org.broadleafoverrides.admin.config |
There is a single ApplicationContext , only in the admin project. This is the default for fresh Broadleaf 5.2+ projects |
@EnableBroadleafAdminRootAutoConfiguration |
org.broadleafoverrides.config , org.broadleafoverrides.admin.config |
There are multiple ApplicationContext s and the override is only for beans in the root (the majority of the Broadleaf beans) only in the admin project. Default for projects upgraded to Broadleaf 5.2 |
@EnableBroadleafAdminServletAutoConfiguration |
org.broadleafoverrides.servlet.config , org.broadleafoverrides.admin.servlet.config |
There are multiple ApplicationContext s and the override is only for beans in the servlet only in the admin project. Default for projects upgraded to Broadleaf 5.2 |
@EnableBroadleafAutoConfiguration |
org.broadleafoverrides.config |
Not used in Broadleaf 5.2, added for completeness |
@EnableBroadleafRootAutoConfiguration |
org.broadleafoverrides.config |
Not used in Broadleaf 5.2, added for completeness |
@EnableBroadleafServletAutoConfiguration |
org.broadleafoverrides.servlet.config |
Not used in Broadleaf 5.2, added for completeness |
Spring's BeanFactoryPostProcessor
BeanDefinitionPostProcessor
and BeanPostProcessor
interfaces
There might be instances where you do not want to override the Broadleaf beans but instead need to customize properties or members of a Broadleaf bean. Spring has some great out of the box abilities to further refine and customize beans within the ApplicationContext
:
Spring Interface | Use When... |
---|---|
BeanFactoryPostProcessor | You want to change a bean definition before any beans are instantiated |
BeanDefinitionRegistryPostProcessor | You need to modify a bean definition that a BeanFactoryPostProcessor depends on, or add additional BeanFactoryPostProcessors |
BeanPostProcessor | You want the original bean definition to be active and instantiate the bean but you want to customize the actual bean instance further (like change properties, modify members, etc) |