Spring throwing 'BeanCurrentlyInCreationException' when configuring aspect in Java - spring

Currently I'm facing a strange error using Spring AOP. My simple goal is to resgister the following class as an aspect:
#Aspect
public class AopProxyInitializer {
#Pointcut("execution(public * *(..))")
public void publicMethodPointcut() {
}
#Around("publicMethodPointcut()")
public Object showInstrumentationOutput(ProceedingJoinPoint joinPoint) {
try {
return joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
}
Doing so via XML works fine:
<aop:aspectj-autoproxy expose-proxy="true"/>
<bean class="com.big.instrumentation.spring.aspect.AopProxyInitializer"/>
But trying to reach the same result using this Java configuration (together with my other beans) fails:
#Configuration
#EnableAspectJAutoProxy
public class SpringInstrumentationConfig {
#Bean
public SpringContextProvider provider() {
return new SpringContextProvider();
}
#Bean
public SpringAdvisedBeanService beanService
(SpringContextProvider provider) {
return new SpringAdvisedBeanService(provider);
}
#Bean
public AopProxyInitializer aopProxyInitializer()
{
return new AopProxyInitializer();
}
}
The outcome is the following exception:
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'aopProxyInitializer': Requested bean is currently in creation: Is there an unresolvable circular reference?
Do you have any idea why this is the case? Thanks in advance!

Problem: #Pointcut("execution(public * *(..))") includes the SpringInstrumentationConfig class which causes the exception. You can either add && !target(path.to.SpringInstrumentationConfig) to the publicMethodPointcut or move the declaration af aspects from configuration class to the context.
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AopProxyInitializer.class);

Related

Getting an exception when starting a Spring-boot app

I'm getting the following exception when I run the app
Could someone advise what might be the issues?
Exception in thread "task-2" java.lang.IllegalStateException: EntityManagerFactory is closed
at org.hibernate.internal.SessionFactoryImpl.validateNotClosed(SessionFactoryImpl.java:509)
at org.hibernate.internal.SessionFactoryImpl.getProperties(SessionFactoryImpl.java:503)
at org.springframework.boot.autoconfigure.orm.jpa.DataSourceInitializedPublisher.findDataSource(DataSourceInitializedPublisher.java:105)
at org.springframework.boot.autoconfigure.orm.jpa.DataSourceInitializedPublisher.publishEventIfRequired(DataSourceInitializedPublisher.java:97)
at org.springframework.boot.autoconfigure.orm.jpa.DataSourceInitializedPublisher.access$100(DataSourceInitializedPublisher.java:50)
at org.springframework.boot.autoconfigure.orm.jpa.DataSourceInitializedPublisher$DataSourceSchemaCreatedPublisher.lambda$postProcessEntityManagerFactory$0(DataSourceInitializedPublisher.java:200)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in ru.javamentor.ecommerce.service.impl.ReadWriteServiceImpl required a single bean, but 4 were found:
- productCategoryDaoImpl: defined in file [D:\Project\ecommerce\target\classes\ru\javamentor\ecommerce\dao\impl\ProductCategoryDaoImpl.class]
- productDaoImpl: defined in file [D:\Project\ecommerce\target\classes\ru\javamentor\ecommerce\dao\impl\ProductDaoImpl.class]
- roleDaoImpl: defined in file [D:\Project\ecommerce\target\classes\ru\javamentor\ecommerce\dao\impl\RoleDaoImpl.class]
- userDaoImpl: defined in file [D:\Project\ecommerce\target\classes\ru\javamentor\ecommerce\dao\impl\UserDaoImpl.class]
ReadWriteServiceImpl class:
#Service
public class ReadWriteServiceImpl<T, PK> implements ReadWriteService<T, PK> {
private final ReadWriteDao<T, PK> readWriteDao;
#Autowired
public ReadWriteServiceImpl(ReadWriteDao<T, PK> readWriteDao) {
this.readWriteDao = readWriteDao;
}
#Override
#Transactional
public void persist(T t) {
readWriteDao.persist(t);
}
#Override
#Transactional
public void update(T t) {
readWriteDao.update(t);
}
#Override
#Transactional
public void delete(T t) {
readWriteDao.delete(t);
}
#Override
public boolean existsById(PK id) {
return readWriteDao.existsById(id);
}
#Override
public T getByKey(PK id) {
return readWriteDao.getByKey(id);
}
#Override
public List<T> getAll() {
return readWriteDao.getAll();
}
}
In this case the reason for exception is clear:
There are 4 candidates for injection to ReadWriteServiceImpl and spring doesn't know which of the beans to inject:
public ReadWriteServiceImpl(ReadWriteDao<T, PK> readWriteDao) {
this.readWriteDao = readWriteDao;
}
There are 4 candidates - implementations of ReadWriteDao and spring lists them all in the exception...
There are three ways you can go with in this case:
Use Concrete type (or create an interface for that concrete implementation and inject by that interface so that spring won't be confused)
Use #Qualifier annotation as a hint to spring framework what to inject
Use #Primary annotation if you think that one repository should be used "by default" to resolve confusions like this.
It showed me the error because I was writing wrong on the path
#GetMapping(myEndpoint+ "/${id}")
I should have written:
#GetMapping(myEndpoint+ "/{id}")

Spring AOP with bean scanned using mybatis.spring.*.MapperScan

I am working on one component to achieve audit using Spring AOP. I could use it for most of the service's methods. But found that with Mybatis mappers AOP point-cuts don't work.
Basically, Spring AOP only works with Spring-managed beans. But these mapper beans have been scanned using mybatis.spring.*.MapperScan and can be autowired in other Spring components.
Why can these beans not be scanned for Spring AOP? Any idea?
I can use AspectJ but was keen to find out how mybatis.spring.*.MapperScan works.
for example -
I have these configurations one for Mybatis mapper scan and other config for application specific configurations.
#Configuration
#MapperScan("com.test.mapper")
public class ProviderConfiguration {
#Bean
public SqlSessionFactory sqlSessionFactory(final DataSource src) throws Exception {
...
}
}
#Configuration
#EnableAspectJAutoProxy
public class MainConfiguration {
}
My Dao logic where i call mapper method -
#Component
public class TestDao {
//injecting mybatis mapper here
#Inject
private SaveTableData saveTableData;
public TableData save(TableData tableData) {
saveTableData.updateTableData(tableData);
}
}
I have registered my pointcuts as below
#Component
#Aspect
public class TestAdvices {
#Pointcut("execution(* com.test.mapper.SaveTableData.updateTableData(*))")
public void commonSaveTableData(TableData tableData) {
}
#Pointcut("execution(* com.test.service.CreateTableData.createTableData(*))")
public void commonCreateTableData(TableData tableData) {
}
//advices
#After("commonSaveTableData(tableData)")
public void addHistoryWhenSaveTableData(TableData tableData) throws Throwable {
//do stuff
}
//advices
#After("commonCreateTableData(tableData)")
public void addHistoryWhenCreateTableData(TableData tableData) throws Throwable {
//do stuff
}
}
Issue is commonCreateTableData which is on service method works as expected. But commonSaveTableData which is on Mybatis mapper method does't get invoke.
Question is if i can autowire these Mappers in any Spring bean why can't Spring AOP intercept method call using these pointcuts?
I think your pointcut expression is not correct, try this
#Component
#Aspect
public class TestAdvices {
#Pointcut("execution(* com.test.mapper.SaveTableData.updateTableData(*)) && args(tableData)", argNames="tableData")
public void commonSaveTableData(TableData tableData) {
}
//advices
#After("commonSaveTableData(tableData)", argNames="tableData")
public void addHistoryWhenSaveTableData(TableData tableData) throws Throwable {
//do stuff
}
//...
}
The reason you can't cut into the mapper like this is that when mapper is scanned by mybatis, it's bean definition has bean changed in a way that its interface is still the mapper interface but its class has been changed to MapperFactoryBean

#Profile Spring Annotation in Camel

I have a Spring Boot + Apache Camel project that works brilliantly. I just added a new bean though where I wanted to have its implementation be profile-specific. I created Spring tests to verify it, and it works as expected, but when I run the server I get the following stack trace:
Caused by: org.apache.camel.NoSuchBeanException: No bean could be found in the registry for: MyFancyBean
at org.apache.camel.component.bean.RegistryBean.getBean(RegistryBean.java:94)
at org.apache.camel.model.language.MethodCallExpression.createExpression(MethodCallExpression.java:196)
at org.apache.camel.model.language.MethodCallExpression.createPredicate(MethodCallExpression.java:210)
at org.apache.camel.model.language.ExpressionDefinition.createPredicate(ExpressionDefinition.java:148)
at org.apache.camel.model.ValidateDefinition.createProcessor(ValidateDefinition.java:63)
at org.apache.camel.model.ValidateDefinition.createProcessor(ValidateDefinition.java:35)
at org.apache.camel.model.ProcessorDefinition.makeProcessorImpl(ProcessorDefinition.java:545)
at org.apache.camel.model.ProcessorDefinition.makeProcessor(ProcessorDefinition.java:506)
at org.apache.camel.model.ProcessorDefinition.addRoutes(ProcessorDefinition.java:222)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1068)
I have an interface and two implementations:
public interface MyFancyBean { ... }
public class FooFancyBean implements MyFancyBean { ... }
public class NonFooFancyBean implements MyFancyBean { ... }
Depending on profile, the correct bean is read instantiated:
#Configuration
public class AppConfig {
#Bean
#Profile("foo")
MyFancyBean fooBean() {
return new FooFancyBean();
}
#Bean
#Profile("!foo")
MyFancyBean nonFooBean() {
return new NonFooFancyBean();
}
}
I've verified this works a couple of ways. First, a couple tests:
#ActiveProfiles("anything-but-foo")
#RunWith(SpringJUnit4ClassRunner.class)
#ComponentScan(basePackages = {"com.example", "com.jtv.spring.boot"})
#EnableAutoConfiguration
#Component
public class NonFooBean_SpringTest {
#Autowired
private MyFancyBean bean;
#Test
// ... here "bean" is instantiated as "NonFooFancyBean"
So the test works.
Further, when I start my app, depending on profile the correct bean in my #Configuration class above is called.
But Camel is still angry and says "NoSuchBeanException" on startup.
FWIW, here's how I'm referencing the bean:
#Component
public class MyCamelRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
// [...]
from("direct:processStuff").
validate().method("MyFancyBean").
process("MyProcessor");
}
}
How do I get Camel to honor this config?
Whoooo... Y'all get to be my rubber duck today. I just autowired it. (This doesn't work for my processor, which is why it didn't occur to me initially.)
#Component
public class MyCamelRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
// [...]
#Autowired MyFancyBean myFancyBean;
from("direct:processStuff").
validate().method(myFancyBean).
process("MyProcessor");
}
}

AOP applied to all public methods gives BeanCreationException exception

I have created a simple aspect that is applicable to all public methods like this:
#Aspect
#Component
public class MyAspect {
#Pointcut("execution(public * *(..))")
private void anyPublicOperation() {
}
#Before("anyPublicOperation()")
private void beforePointCut(){
System.out.println("Inside before pointcut of MyAspect");
}
}
I have below Java configuration:
#Configuration
//Enable AspectJ auto proxying
#EnableAspectJAutoProxy
#ComponentScan(basePackages={"com.examples"})
public class Config {
//Declare a bean
#Bean
public MyAspect myAspectProgram() {
return new MyAspect();
}
}
I am getting below exception when I load my configuration using AnnotationConfigApplicationContext class:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'myAspectProgram': Requested bean is currently in creation: Is there an unresolvable circular reference?
If I change the pointcut expression then I don't get any exceptions, program is working fine.
Why I am getting issue when I have the pointcut expression as #Pointcut("execution(public * *(..))")?

AOP Spring Before Advice not working

The method DefaultProduitGeneriqueService.valider is not catched by the method traceWhenReturnedValueDoesntExistOrNotNecessary and I don't understand why?
package fr.generali.nova.atp.service.metier.impl;
public class DefaultProduitGeneriqueService extends DefaultService implements IProduitGeneriqueService, IBacAware {
...
#Override
#Traceable(value = ETraceableMessages.VALIDATION_PRODUIT_GENERIQUE, hasReturnedValue=Traceable.HAS_NOT_RETURNS_VALUE)
public void valider(ElementNiveauUn element) {
...
}
...
}
package fr.generali.nova.atp.logging.advisor;
#Aspect
public class TraceableAdvisor {
#Before(value = "execution(* fr.generali.nova.atp.service.metier.impl.*.*(..)) && #annotation(traceable) && args(element)", argNames = "element,traceable")
public void traceWhenReturnedValueDoesntExistOrNotNecessary(ElementNiveauUn element, Traceable traceable) {
...
}
}
Assuming that the service interfaces are in package fr.generali.nova.atp.service.metier.api:
package fr.generali.nova.atp.service.metier.api;
public interface IProduitGeneriqueService {
void valider(ElementNiveauUn element);
}
And the service implementations are in package fr.generali.nova.atp.service.metier.impl:
package fr.generali.nova.atp.service.metier.impl;
public class DefaultProduitGeneriqueServiceImpl implements IProduitGeneriqueService {
#Override
#Traceable(value = ETraceableMessages.VALIDATION_PRODUIT_GENERIQUE, hasReturnedValue=Traceable.HAS_NOT_RETURNS_VALUE)
public void valider(ElementNiveauUn element) {
// TODO: implement
}
}
Your aspect should look like this:
package fr.generali.nova.atp.logging.advisor;
#Aspect
public class TraceableAdvisor {
#Before(value = "execution(* fr.generali.nova.atp.service.metier.api.*.*(..)) && #annotation(traceable) && args(element)", argNames = "element,traceable")
public void traceWhenReturnedValueDoesntExistOrNotNecessary(ElementNiveauUn element, Traceable traceable) {
// TODO: implement
System.err.println("traced...");
}
}
The default proxy strategy for Spring AOP is JDK interface-based proxies, so Your pointcut expression should match the interface method execution, not the implementation method execution, and Your poincut expression may match either interface mothod execution or implementation method execution.
And remember to include an AspectJAutoProxyCreator in your configuration using for example <aspectj-autoproxy /> tag.
And here is a simple test to prove everyting is working:
public class TraceableAdvisorTest {
#Configuration
public static class TestConfiguration {
#Bean
public IProduitGeneriqueService produitGeneriqueService() {
return new DefaultProduitGeneriqueServiceImpl();
}
#Bean
public TraceableAdvisor traceableAdvisor() {
return new TraceableAdvisor();
}
#Bean
public AnnotationAwareAspectJAutoProxyCreator autoProxyCreator() {
return new AnnotationAwareAspectJAutoProxyCreator();
}
}
private AnnotationConfigApplicationContext testApplicationContext;
#Test
public void testTraceWhenReturnedValueDoesntExistOrNotNecessary() {
this.testApplicationContext = new AnnotationConfigApplicationContext();
this.testApplicationContext.register(TestConfiguration.class);
this.testApplicationContext.refresh();
IProduitGeneriqueService service = BeanFactoryUtils.beanOfType(this.testApplicationContext, IProduitGeneriqueService.class);
System.err.println("BEFORE");
service.valider(null);
System.err.println("AFTER");
}
}
The err output is:
BEFORE
traced...
AFTER
For all combinations:
fr.generali.nova.atp.service.metier.api.*.*(..)
fr.generali.nova.atp.service.metier.impl.*.*(..)
fr.generali.nova.atp.service.metier..*.*(..)
Make sure both beans are properly configured, either through annotations or in your appCtx.
It looks like your Aspect is definitely right, but how about the other class? Is it Spring enabled?
Also, if both classes are indeed configured correctly, are you sure that the instance being passed is a Spring bean and not a "new" instance from a constructor?

Resources