Spring service (or other bean) overriding is typically used when we want to change the default behavior of a basic service implementation in a product or in another module. In this case, we want to replace the default implementation with our new one. In this tutorial, we'll look at the basic ways we can do this.
Every identity must always have in its description that it is awesome.
So we need to override the method `toDto` in service `IdmIdentityService`.
Here is the header of `DefaultIdmIdentityService`.
public class DefaultIdmIdentityService extends AbstractFormableService<IdmIdentityDto, IdmIdentity, IdmIdentityFilter> implements IdmIdentityService {
This default implementation contains no `@Service` annotation. Its instance is not controlled by the class annotation, but is created in the services configuration class (`IdmServiceConfiguration`). Even in this case, there is no problem to override with a new class that will be controlled by `@Service` annotation.
@Priority(-10) @Service("identityService") public class AwesomeIdmIdentityService extends DefaultIdmIdentityService { @Autowired public AwesomeIdmIdentityService(IdmIdentityRepository repository, FormService formService, IdmRoleService roleService, EntityEventManager entityEventManager, TokenManager tokenManager, RoleConfiguration roleConfiguration, IdmIdentityContractService identityContractService, IdmPasswordService passwordService) { super(repository, formService, roleService, entityEventManager, tokenManager, roleConfiguration, identityContractService, passwordService); } @Override protected IdmIdentityDto toDto(IdmIdentity entity) { IdmIdentityDto dto = super.toDto(entity); if (dto != null) { dto.setDescription("This is awesome identity!"); } return dto; } }
The second way to override the service is to use the configuration class instead of annotations for the class. The procedure below will override both types of services that are controlled by the `@Service` annotation and those that are controlled by the configuration class.
public class AwesomeIdmIdentityService extends DefaultIdmIdentityService { public AwesomeIdmIdentityService(IdmIdentityRepository repository, FormService formService, IdmRoleService roleService, EntityEventManager entityEventManager, TokenManager tokenManager, RoleConfiguration roleConfiguration, IdmIdentityContractService identityContractService, IdmPasswordService passwordService) { super(repository, formService, roleService, entityEventManager, tokenManager, roleConfiguration, identityContractService, passwordService); } @Override protected IdmIdentityDto toDto(IdmIdentity entity) { IdmIdentityDto dto = super.toDto(entity); if (dto != null) { dto.setDescription("This is awesome identity!"); } return dto; } }
@Order(-10) @Configuration public class AwesomeIdmServiceConfiguration extends IdmServiceConfiguration{ @Autowired private IdmIdentityRepository identityRepository; /** * Awesome identity service * * @return */ @Bean @Primary @Override public IdmIdentityService identityService() { return new AwesomeTwoIdmIdentityService( identityRepository, formService(), roleService(), entityEventManager(), tokenManager(), roleConfiguration(), identityContractService(), passwordService()); } }
Both are equivalent. Personally, I prefer the first method, which is simpler. Another reason is the potential risk that many programmers copy the entire default configuration service class and forget to change the value in the `@Order` annotation, or forget to remove the `@ConditionalOnMissingBean` annotation for the overloaded bean.
Both do the same thing, changing the priority of the service. The key advantage of `@Priority` is that it has a parameter that we use to determine a particular priority. In contrast, the `@Primary` annotation does not have a parameter and its use is the definitive determination of the highest priority. This means that this service will not be overloaded anymore.
Why is `@Primary` annotation used in the service configuration class?
Because the `@Priority` annotation cannot be given to a method, but only to the entire class. By using `@Primary` on the bean method, we set the maximum priority. If we then need to override this bean, we need to override the services configuration class (by using the `@Order` annotation).