We are using Spring Boot for our application.
After starting the application, in the runtime we are adding(loading) a new Bean to the existing Applicationcontext.
AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext();
appContext.register(NewBean.class);
appContext.refresh();
after adding the bean we are doing a refresh of applicationContext
During the refresh the MBean is trying to reregister some endpoints and we are getting the following error
(getting error for all these endpoints - requestMappingEndpoint, environmentEndpoint, healthEndpoint, beansEndpoint, infoEndpoint, metricsEndpoint, traceEndpoint, dumpEndpoint,
autoConfigurationAuditEndpoint, shutdownEndpoint, configurationPropertiesReportEndpoint)
Caused by: javax.management.InstanceAlreadyExistsException: org.springframework.boot:type=Endpoint,name=configurationPropertiesReportEndpoint
at com.sun.jmx.mbeanserver.Repository.addMBean(Unknown Source)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(Unknown Source)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(Unknown Source)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(Unknown Source)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(Unknown Source)
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(Unknown Source)
at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:195)
at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:662)
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:605)
Can anyone please tell how to skip this exception?
I have tried the following too
#EnableIntegrationMBeanExport(registration = RegistrationPolicy.REPLACE_EXISTING)
but getting the below exception
Caused by: org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [org.springframework.integration.monitor.IntegrationMBeanExporter#16c5464] with key 'integrationMbeanExporter'; nested exception is javax.management.InstanceAlreadyExistsException: org.springframework.integration.monitor:name=integrationMbeanExporter,type=IntegrationMBeanExporter
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:609)
at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:534)
at org.springframework.jmx.export.MBeanExporter.afterPropertiesSet(MBeanExporter.java:416)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
... 22 more
Caused by: javax.management.InstanceAlreadyExistsException: org.springframework.integration.monitor:name=integrationMbeanExporter,type=IntegrationMBeanExporter
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324)
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522)
at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:195)
at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:662)
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:599)
... 26 more
Before you call refresh on an existing ApplicationContext, you should first destroy it else beans keep running.
AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext();
appContext.register(NewBean.class);
appContext.refresh();
What you show here is that you are constructing a new context instead of reusing an existing one. The register method is also intended for #Configuration classes not arbitrary beans. If you want to add those just use one of the methods on the ApplicationContext like, registerSingleton. But in general adding beans at runtime should be a bad thing (imho).
Some applicationContext can refresh times, but not AnnotationConfigApplicationContext.
when you construct AnnotationConfigApplicationContext, which had run the refresh method, so it will be reported exception, you can destroy it first, and then refresh
Related
I'm receiving a NullPointerException in a method with the Annotation #Bean, but before I never got this NullPointerException there:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [dev.teamnight.command.CommandFramework]: Circular reference involving containing bean 'config' - consider declaring the factory method as static for independence from its containing instance. Factory method 'commandFramework' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
... 68 common frames omitted
Caused by: java.lang.NullPointerException: null
at dev.teamnight.nightbot.Config.commandFramework(Config.java:84) ~[classes/:na]
at dev.teamnight.nightbot.Config$$EnhancerBySpringCGLIB$$2d4937ec.CGLIB$commandFramework$3(<generated>) ~[classes/:na]
at dev.teamnight.nightbot.Config$$EnhancerBySpringCGLIB$$2d4937ec$$FastClassBySpringCGLIB$$3fbdfefd.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at dev.teamnight.nightbot.Config$$EnhancerBySpringCGLIB$$2d4937ec.commandFramework(<generated>) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
... 69 common frames omitted
The code of the file causing the Exception:
#Configuration
#PropertySource("file:bot.properties")
public class Config {
#Autowired
private ShardManager shardManager;
#Autowired
private PermissionProvider permissionProvider;
#Autowired
private LanguageProvider languageProvider;
#Autowired
private PrefixProvider prefixProvider;
#Autowired
private HelpProvider helpProvider;
#Bean
public ShardManager shardManager() throws LoginException, IllegalArgumentException {
DefaultShardManagerBuilder builder = DefaultShardManagerBuilder.createDefault(this.botToken)
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.setMemberCachePolicy(MemberCachePolicy.ALL)
.setStatus(OnlineStatus.IDLE)
.setShardsTotal(this.totalShards)
.addEventListeners(Arrays.asList(this.jdaListener()));
return builder.build();
}
#Bean
public CommandFramework commandFramework() {
Logger log = LogManager.getLogger();
//Line causing the error below!
log.error("Name of helpProvider: " + this.helpProvider.getClass().getCanonicalName());
return new FrameworkBuilder()
.addOwners(Arrays.stream(this.ownerIds).filter(ownerId -> ownerId.matches("^(\\d)+$")).map(ownerId -> Long.parseLong(ownerId)).collect(Collectors.toList()))
.setLogger(NightBot.logger())
.allowBots(false)
.allowDM(false)
.allowMention(true)
.allowRainbowColors(true)
.withPrefixProvider(this.prefixProvider)
.withLanguageProvider(this.languageProvider)
.withPermissionProvider(this.permissionProvider)
.withHelpProvider(this.helpProvider)
.withCustomArgumentProcessor(new NamedArgumentProcessor())
.registerClient(this.shardManager)
.build();
}
}
As I said, before the code fully worked, and I changed nothing on the Config.java file, so this error is confusing me as hell.
You are seeing this NullPointerException because the autowired HelperProvider not being injected in.
You are attempting to call .getClass() on a null object.
General Dependency Injection Debugging
Just want to add a quick basic mentions, since the main answer to this question has to make some assumption on your codebase. There are several things that you want to check when dependency injection fails.
Configuration files - Are these being loaded in correctly. Is your component scanning recently disabled?
Do your Components have the necessary #Component and or #Service/#Controller/#Repository annotations?
The Likely Root Problem - Circular Reference - BeanInstantiationException
There is also a mention of a circular reference in your stacktrace which is likely what is causing the problem.
Caused by: org.springframework.beans.BeanInstantiationException: Circular reference involving containing bean 'config' - consider declaring the factory method as static for independence from its containing instance. Factory method 'commandFramework' threw exception; nested exception is java.lang.NullPointerException
Since you received this error message, you have introduced a circular reference. This means... that a component relies on a component which relies on that component.
For example:
#Component
class HelperProvider {
#Autowired
Config config;
}
and
#Configuration
class Config {
#Autowired
HelperProvider helperProvider
}
This pattern will stump the spring framework because they rely on each other to load each component up. It can happen if you introduce a dependency further down the line. Say HelperProvider requires HelperHelperProvider which requires Config.
You will want to check for any new injections of Config or CommandFramework in your recent edits.
What you should do
You will want to redesign your configuration to break it's reliance on the HelperProvider. Doing this can resolve a lot of headaches in your future.
What you shouldn't do
It's possible to lazyload the component or configuration with #Lazy annotation. That way the bean is only instantiated upon invocation. It's recommended if you want to learn more nuances in booting up the Spring ApplicationContext, but it will become a nightmare to maintain down the road.
The error you are getting is most probably because you have a cyclic dependency in your project. And since you are getting it in commandFramework method as illustrated in error it is because of the HelpProvider class in which you are using the Config class again.
So when spring is creating a bean of Config it has to create a bean of HelpProvider which in terms wants to create a bean of Config(Autowired in HelpProvider) and leads to a never ending cycle giving the error. Also check if HelpProvider has the #component annotataion.
Config -> HelpProvider -> Config -> HelpProvider -> Config .............
Solution:-
Either you can remove the config from the HelpProvider and try to redesign it.
Use #Lazy on Config in HelpProvider which will load this dependency on object instantiation. Will suggest it as a last resort.
I am trying to use the #Value annotation to grab the URI and database name while creating a SpringBootMongock object via SpringBootMongockBuilder and during mvn install it attempts to load the application context and fails because my Spring Contract tests cannot connect to the database in my application.yml file. Which I do not want while building my app anyways.
I have gotten around this by injecting the Environment object in my method signature but I don't understand why the #Value is not working. I have annotated the class with #Configuration which works fine.
Update: I still need to grab the URI from the yaml file to create my MongoClient using the #Bean annotation..
#Configuration
public class MongockConfiguration {
#Value(${spring.data.mongodb.uri})
private String uri;
#Bean
public MongoClient mongoClient(){
return MongoClients.create(uri);
}
#Bean
public SpringBootMongock mongock(Application context, Environment environment) throws Exception {
return new SpringBootMongockBuilder(mongoClient(), dbname, ChangeLogOne.class.getPackage().getName()).setEnabled(migrate).setApplicationContext(applicationContext).build();
}
some of the above values I pull from the Environment object as the #Value wasn't working for me .. no need to provide exact values here
exception is
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongock' defined in class path resource [blah/dht/mcs/registrationservice/config/MongockConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.github.cloudyrock.mongock.SpringBootMongock]: Factory method 'mongock' threw exception; nested exception is com.mongodb.MongoSecurityException: Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName='testUser', source='admin', password=<hidden>, mechanismProperties={}}
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.github.cloudyrock.mongock.SpringBootMongock]: Factory method 'mongock' threw exception; nested exception is com.mongodb.MongoSecurityException: Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName='testUser', source='admin', password=<hidden>, mechanismProperties={}}
Caused by: com.mongodb.MongoSecurityException: Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName='testUser', source='admin', password=<hidden>, mechanismProperties={}}
Caused by: com.mongodb.MongoCommandException: Command failed with error 18 (AuthenticationFailed): 'Authentication failed.' on server localhost:27017. The full response is { "ok" : 0.0, "errmsg" : "Authentication failed.", "code" : 18, "codeName" : "AuthenticationFailed" }
and for the record with the values hardcoded vs using the #Value annotation everything works as expected.
The issue is not related to Mongock, but I see pretty clear that is due to MongoClient not being injected whenever you get the error.
As you mentioned it works when you provide the uri hardcoded, I was tempted to say that Spring doesn't find the spring.data.mongodb.uri, but if I am not wrong, it would fail saying that property is not found, rather than the error you are getting, as you are not providing a default value.
Anyway, it's something around there, for some reason, whenever you are running this and fails, the MongoClient is not added to the context for some reason.
I hope you find it useful.
I have a Java Application that uses Armeria for a Web Service. When I create my Hibernate SessionFactory in the main method it works fine. But I am trying to create the SessionFactory when a certain Http Endpoint is called. In the handler method the session factory can not be created
Exception in thread "Thread-1" org.hibernate.internal.util.config.ConfigurationException: Unable to perform unmarshalling at line number 0 and column 0 in RESOURCE hibernate.cfg.xml. Message: null
Caused by: javax.xml.bind.JAXBException
- with linked exception:
[java.lang.ClassNotFoundException: com/sun/xml/bind/v2/ContextFactory]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:226)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:441)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:641)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)
at org.hibernate.boot.cfgxml.internal.JaxbCfgProcessor.unmarshal(JaxbCfgProcessor.java:122)
... 17 more
Caused by: java.lang.ClassNotFoundException: com/sun/xml/bind/v2/ContextFactory
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at javax.xml.bind.ContextFinder.safeLoadClass(ContextFinder.java:577)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:224)
... 21 more
All I could find about this error is that JaxB is not provided for Java > 8 but i am using Java 8 and it works fine if I just create it at Application launch.
I believe it's some sort of class path conflict. In Java 8, the following code fails with ClassNotFoundException: com/sun/xml/bind/v2/ContextFactory, as reported in the question:
public class MyService {
#Get("/start")
public HttpResponse start() throws Exception {
final StandardServiceRegistryBuilder registryBuilder =
new StandardServiceRegistryBuilder().configure();
...
}
}
However, the problem goes away after upgrading to a newer Java version, such as Java 11.
Fortunately, the problem can be worked around by specifying the context class loader explicitly:
#Get("/start")
public HttpResponse start() throws Exception {
Thread.currentThread().setContextClassLoader(MyService.class.getClassLoader());
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
final StandardServiceRegistryBuilder registryBuilder =
new StandardServiceRegistryBuilder().configure();
...
}
I'm trying to migrate from spring 3.0.5 to spring 4.1.X .
Spring 3 has Class named as "org.springframework.scheduling.quartz.CronTriggerBean"
But Spring 4 doesn't include this class name.
[5/28/15 20:10:16:798 EDT] 00000092 ClassPathXmlA W
org.springframework.context.support.AbstractApplicationContext
__refresh Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.CannotLoadBeanClassException: Cannot
find class [org.springframework.scheduling.quartz.CronTriggerBean] for
bean with name 'beanIdName' defined in class path resource
[config/spring/WxsCacheContext.xml]; nested exception is
java.lang.ClassNotFoundException:
org.springframework.scheduling.quartz.CronTriggerBean
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1328)
I have tried alternative like "spring-support" which has the same class. But no luck.
After getting that jar, it is giving errors about the quartz
[5/28/15 15:37:02:665 EDT] 0000006e SystemOut O ERROR (?:?) -
java.lang.Exception: Bean from
SpringUtils.getSpringBean(hostnameVerifierSetter) error message:
Unable to initialize group definition. Group resource name
[classpath*:beanRefFactory.xml], factory key [beanContext]; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'beanContext' defined in URL
[file:/C:/Program%20Files%20(x86)/IBM/WebSphere/AppServer/profiles/AppSrv01/installedApps/cellName/Project.ear/configurations/beanRefFactory.xml]:
Bean instantiation via constructor failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate
[org.springframework.context.support.ClassPathXmlApplicationContext]:
Constructor threw exception; nested exception is
java.lang.NoClassDefFoundError: org.quartz.impl.JobDetailImpl
From Spring 3.1+, Change the Class names for the CronTriggerFactoryBean & JobDetailFactoryBean as like below
org.springframework.scheduling.quartz.CronTriggerBean
org.springframework.scheduling.quartz.CronTriggerFactoryBean
org.springframework.scheduling.quartz.JobDetailBean
org.springframework.scheduling.quartz.JobDetailFactoryBean
So your steps are:
Change
CronTriggerBean to CronTriggerFactoryBean
JobDetailBean to
JobDetailFactoryBean
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/quartz/CronTriggerFactoryBean.html
Since Spring3.1, it has changed.
Caused by: java.lang.NullPointerException
at org.springframework.boot.actuate.endpoint.DataSourcePublicMetrics.initialize(DataSourcePublicMetrics.java:64) ~[spring-boot-actuator-1.3.2.RELEASE.jar:1.3.2.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_79]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[?:1.7.0_79]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.7.0_79]
at java.lang.reflect.Method.invoke(Method.java:606) ~[?:1.7.0_79]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:354) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
I disabled the metrics too but no luck
endpoints.enabled=false
endpoints.autoconfig.enabled=false
endpoints.metrics.enabled=false
The DataSourcePublicMetrics bean always gets created, even when the metrics are disabled. This causes a NullPointerException when the database connection is unavailable, causing spring boot not to start.
I am using Hikari datasource and it fails to construct data source object when database is unavailable. Hence NPE from DataSourcePublicMetrics bean. I am able to circumvent the issue creating a Hikari data source that is lazy initialized with database config even when database is unavailable for later use when database becomes available. Not sure why HikariDataSource does not have a constructor for lazy init. It does have a default constructor but database config can't be set using any setter method. This is useful for applications where database is not always necessary to start them up.
public class LazyConnectionDataSource extends HikariDataSource {
public LazyConnectionDataSource(HikariConfig config) {
config.validate();
config.copyState(this);
}
}