AOP applied to all public methods gives BeanCreationException exception - spring

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 * *(..))")?

Related

Circular dependency error for beans in Spring org.springframework.beans.factory.BeanCurrentlyInCreationException:

I have a classes defined as follows :
#Configuration
public class TestConfig extends IntegrationTestConfig {
#Bean
public TestUserManager testUserManager() {
...
}
#Configuration
#Import({BaseTestConfig.class})
public class IntegrationTestConfig {
#Autowired
private TestUserManager ssbTestUserManager;
#Bean
#DependsOn({"testUserManager"})
public TestDeviceFactory testDeviceFactory() {
return new TestDeviceManager();
}
#Configuration
public class BaseTestConfig {
#Bean
public TestUserManager testUserManager() {
...
}
}
When I try to execute it, it gives the error :
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testConfig': Unsatisfied dependency expressed through field 'ssbTestUserManager'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testUserManager': Requested bean is currently in creation: Is there an unresolvable circular reference
How can I fix this issue? I am not able to override the testUserManager() method in TestConfig since it does not directly inherit from BaseTestConfig. IntegrationTestConfig and BaseTestConfig are imported as libraries so I dont have much control there.
I think #DependsOn({"testUserManager"}) is causing issue but not sure how I can resolve it
A circular reference occurs when you have a chain of beans that depends together and a cycle created in the dependency graph.
So, in your case, you've defined an instance of TestUserManager in TestConfig class and uses it in the parent class and it creates a cycle!
The solution is defininig abstract getTestUserManager method in the parent class and override it in the child class with #Bean annotation (If you are using it in other parts of code). You can use that method in your parent class instead of using the variable you've defined.
IntegrationTestConfig:
#Configuration
public abstract class IntegrationTestConfig {
public abstract TestUserManager getTestUserManager();
}
TestConfig:
#Configuration
public class TestConfig extends IntegrationTestConfig {
#Bean
#Override
public TestUserManager getTestUserManager() {
return new TestUserManager();
}
}

Intellij Spring: NoSuchBeanDefinitionException: No bean named 'accountDAO' available

This is driving me nuts. I have the following files, it is a very simple setup.
public class MainApp {
public static void main(String[] args) {
//read the spring config java class
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("Config.class");
//System.out.println("Bean names: " + Arrays.toString(context.getBeanNamesForType(AccountDAO.class)));
//get the bean from spring container
AccountDAO accountDAO = context.getBean("accountDAO", AccountDAO.class);
//call the business method
accountDAO.addAccount();
//close the spring context
context.close();
}
}
Config.java:
#Configuration
#ComponentScan("com.aop")
#EnableAspectJAutoProxy
public class Config {
}
LoggingAspectDemo.java:
#Aspect
#Component
public class LoggingAspectDemo {
//this is where we add all our related advices for the logging
//let's start with an #Before advice
#Before("execution(public void addAccount())")
public void beforeAddAccountAdvice() {
System.out.println("\n=======>>>> Executing #Before advice on method addAccount() <<<<========");
}
}
AccountDAO.java
#Component
public class AccountDAO {
public void addAccount() {
System.out.println(getClass() + ": Doing my Db work: Adding an account");
}
}
Everytime I run the MainApp.java, I get:
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'accountDAO' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1207)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
All the files are under "com.aop" package so #ComponentScan should be scanning all the components. It looks simple enough but I can't get my hands around the problem, can anyone help me where I am going wrong?
You're invoking the constructor of AnnotationConfigApplicationContext with "Config.class" as String argument, but this constructor is actually for invoking with base packages i.e. the argument must be a package name.
Since you want to use it with the Configuration class, use the constructor which accepts Class instance instead i.e.
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

#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");
}
}

Spring Boot Custom AutoConfiguration and Autowire

I am creating a custom AutoConfiguration for Spring Boot. One of the features I was attempting to create was to create one or more Beans dynamically and adding them to the ApplicationContext at runtime.
The problem I ran into was with Autowiring. My #SpringBootApplication class autowires those beans, and since they do not exist yet, autowire fails.
My first solution was to put #Lazy on the autowire, and that solved my problem.
However, I ran into something interesting. I added two beans that I was looking for into the AutoConfiguration code, and of course, it worked. By accident, I only removed one of the beans and re-ran my code. It worked.
#SpringBootApplication
public class SpringBootDemoApplication {
#Autowired
#Qualifier("some_name")
private MyClass myClass;
#Autowired
#Qualifier("another_name")
private MyClass anotherClass;
...
}
#Configuration
public class MyAutoConfigurationClass {
#Bean(name="some_class")
public MyClass myClass () {
return null;
}
}
So the short of it is this. If I defined only one of the beans in my autoconfiguration class, this seems to satisfy Autowired and it does not blow up and when I dynamically add my other beans, both beans are found.
The stipulation is that the Autowired bean that is first, must be the bean that is defined in my autoconfiguration class.
I am running the following:
Spring Boot Starter 1.5.7-RELEASE
Various Spring Framework 4.3.11-RELEASE
Is this a bug? Or is this the way Autowired is supposed to work?
#SpringBootApplication
public class SpringBootDemoApplication {
#Autowired
#Qualifier("myclass")
private MyClass myClass;
#Autowired
#Qualifier("anotherMyClass")
private MyClass anotherMyClass;
...
}
#Configuration
public class MyAutoConfiguration {
private ConfigurableApplicationContext applicationContext;
private final BeanFactory beanFactory;
#Autowired
private MyClassFactory myClassFactory;
public MyAutoConfiguration(ApplicationContext applicationContext, BeanFactory beanFactory) {
this.beanFactory = beanFactory;
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
#PostConstruct
public void init() throws IOException, SQLException {
this.myClassFactory.create(this.applicationContext);
}
// without this #Bean definition SpringBoot will recieve the following error and stop
// AnnotationConfigEmbeddedWebApplicationContext - Exception encountered during context initialization
#Bean(name="myClass")
public DataSource anyNameWillDoItDoesntMatter() {
return null;
};
}
#Component
class MyClassFactory {
public void create(ConfigurableApplicationContext applicationContext) {
applicationContext.getBeanFactory().registerSingleton(name, value);
}
}
So is this expected behavior of #Autowired?

Spring throwing 'BeanCurrentlyInCreationException' when configuring aspect in Java

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);

Resources