A little background:
I am using Spring and Camel together with Java 8.
public static void main(String[] args) throws Exception {
AbstractApplicationContext _context = new ClassPathXmlApplicationContext(
"application-context.xml");
_context.registerShutdownHook();
MessageRoute _messageRoute = (MessageRoute) _context.getBean("messageRoute");
SpringCamelContext _camelContext = _context.getBean(SpringCamelContext.class);
_messageRoute.setContext(_camelContext);
_camelContext.addRoutes(_messageRoute);
Object lock = new Object();
synchronized (lock) {
lock.wait();
}
((ClassPathXmlApplicationContext) _context).close();
}
[main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties]
[main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment]
[main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null]
[main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'messageRoute'
[main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.apache.camel.spring.SpringCamelContext#0'
[main] DEBUG o.a.camel.spring.SpringCamelContext - Adding routes from builder: Routes: []
[main] DEBUG o.a.camel.spring.SpringCamelContext - Adding routes from builder: Routes: []
I have tried using DefaultCamelContext as well but the problem is it's just not adding the route class. The MessageRoute class is a simple class extending the RouteBuilder. My observation tells me the line containing: _context.getBean("messageRoute") might have an issue because it's not really passing any route to the RouteBuilder reference.
Never mind I fixed it! Camel wasn't adding an instance of the Route class sitting inside the spring container because in the configure method, one needs an actual path saying from().to().
Pretty funny though that it wasn't throwing any error and even refused the add the ApplicationContext bean to routes.
To add Java routes in XML, just use <routeBuilder ref="myBeanName"/> inside <camelContext>
See the Camel documentation: http://camel.apache.org/spring.html at the section Using Java Code
Related
I use spring shell (not spring boot) in my app and want to disable debug logs.
After I run commands console print some debug logs. For example:
"DEBUG - DefaultListableBeanFactory - Returning cached instance of singleton bean 'myPromptProvider'"
"DEBUG - DefaultListableBeanFactory - Returning cached instance of singleton
bean 'defaultPromptProvider'"
Note that i run my app in windows cmd with java - jar *.jar
Here is my code:
#Component
public class Test implements CommandMarker {
//------------------------------------------------------ create
#CliCommand(value = {"test"})
public void test(
#CliOption(key = {"str"}, mandatory = true) final String str
) {
System.out.println(str);
}
}
and here is output:
spring-shell>test --str aaa
aaa
DEBUG - DefaultListableBeanFactory - Returning cached instance of singleton bean 'defaultPromptProvider'
DEBUG - DefaultListableBeanFactory - Returning cached instance of singleton bean 'myPromptProvider'
I want to eliminate those debug lines.
situation
I have a spring boot application that run a simple REST Service. I want to test this service. Since I love Spock Framework I'd love to use it here but I can't get pass the issue with the Spring Configuration.
problem
The test itself does run but is throwing a java.net.ConnectException: Connection refused: connect exception. The issue here is that the actual application I want to test against is not running - therefore there is not REST interface available. How can I assure that the actual application is running before the test runs? Using JUnit this concern was kinda trivial since Spring has its annotations for that. But what about Spock?
Edit: I tried to use the following article: http://henningpetersen.com/post/18/testing-spring-mvc-controllers-with-spock
RestHandler.java
#RestController
public class RestHandler {
private #Autowired ExecutionService executionService;
public RestHandler(ExecutionService executionService) {
this.executionService = executionService;
}
#RequestMapping(value = "/toolbox/exec", method = POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.TEXT_PLAIN_VALUE)
public String executeTool(#RequestBody Tool tool) {
executionService.execute(tool);
return "thanks";
}
}
ToolExecutor.java
#SpringBootApplication
public class ToolExecutor {
public static void main(String[] args) {
SpringApplication.run(ToolExecutor.class, args);
}
}
RestHandlerTest.groovy
#SpringBootTest
class RestHandlerTest extends Specification {
def someService = Mock(ExecutionService)
def underTest = new RestHandler(someService);
def mockMvc = MockMvcBuilders.standaloneSetup(underTest).build()
#Shared
def client = new RESTClient("http://localhost:603/toolbox/exec")
def "ExecuteToolTest"() {
when: "If POST has valid JSON format"
Closure object = { "{\"name\":\"test\",\"parameters\":[\"abc\",\"def\"]}" }
def response = client.request(Method.POST, object);
then:
with(response){
data.text == "thanks"
status == 200
}
}
}
LOG
15:22:07.601 [main] DEBUG org.springframework.core.env.StandardEnvironment - Adding [systemProperties] PropertySource with lowest search precedence
15:22:07.605 [main] DEBUG org.springframework.core.env.StandardEnvironment - Adding [systemEnvironment] PropertySource with lowest search precedence
15:22:07.605 [main] DEBUG org.springframework.core.env.StandardEnvironment - Initialized StandardEnvironment with PropertySources [systemProperties,systemEnvironment]
15:22:07.855 [main] DEBUG org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder$StaticRequestMappingHandlerMapping - Looking for request mappings in application context: org.springframework.test.web.servlet.setup.StubWebApplicationContext#17f9d882
15:22:07.897 [main] DEBUG org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder$StaticRequestMappingHandlerMapping - 2 request handler methods found on class com.company.toolbox.components.executor.RestHandler: {public void com.company.toolbox.components.executor.RestHandler.isAlive()={[/toolbox/exec],methods=[GET]}, public java.lang.String com.company.toolbox.components.executor.RestHandler.executeTool(com.company.toolbox.commons.Tool)={[/toolbox/exec],methods=[POST],consumes=[application/json],produces=[text/plain]}}
15:22:07.900 [main] INFO org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder$StaticRequestMappingHandlerMapping - Mapped "{[/toolbox/exec],methods=[GET]}" onto public void com.company.toolbox.components.executor.RestHandler.isAlive()
15:22:07.907 [main] INFO org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder$StaticRequestMappingHandlerMapping - Mapped "{[/toolbox/exec],methods=[POST],consumes=[application/json],produces=[text/plain]}" onto public java.lang.String com.company.toolbox.components.executor.RestHandler.executeTool(com.company.toolbox.commons.Tool)
15:22:08.285 [main] DEBUG org.jboss.logging - Logging Provider: org.jboss.logging.Slf4jLoggerProvider
15:22:08.286 [main] INFO org.hibernate.validator.internal.util.Version - HV000001: Hibernate Validator 5.3.4.Final
15:22:08.307 [main] DEBUG org.hibernate.validator.internal.engine.resolver.DefaultTraversableResolver - Cannot find javax.persistence.Persistence on classpath. Assuming non JPA 2 environment. All properties will per default be traversable.
15:22:08.317 [main] DEBUG org.hibernate.validator.internal.engine.ConfigurationImpl - Setting custom MessageInterpolator of type org.springframework.validation.beanvalidation.LocaleContextMessageInterpolator
15:22:08.318 [main] DEBUG org.hibernate.validator.internal.engine.ConfigurationImpl - Setting custom ParameterNameProvider of type com.sun.proxy.$Proxy26
15:22:08.320 [main] DEBUG org.hibernate.validator.internal.xml.ValidationXmlParser - Trying to load META-INF/validation.xml for XML based Validator configuration.
15:22:08.323 [main] DEBUG org.hibernate.validator.internal.xml.ResourceLoaderHelper - Trying to load META-INF/validation.xml via TCCL
15:22:08.324 [main] DEBUG org.hibernate.validator.internal.xml.ResourceLoaderHelper - Trying to load META-INF/validation.xml via Hibernate Validator's class loader
15:22:08.324 [main] DEBUG org.hibernate.validator.internal.xml.ValidationXmlParser - No META-INF/validation.xml found. Using annotation based configuration only.
15:22:08.386 [main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter - Looking for #ControllerAdvice: org.springframework.test.web.servlet.setup.StubWebApplicationContext#17f9d882
15:22:08.422 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Looking for exception mappings: org.springframework.test.web.servlet.setup.StubWebApplicationContext#17f9d882
15:22:08.442 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Initializing servlet ''
15:22:08.452 [main] DEBUG org.springframework.web.context.support.StandardServletEnvironment - Adding [servletConfigInitParams] PropertySource with lowest search precedence
15:22:08.452 [main] DEBUG org.springframework.web.context.support.StandardServletEnvironment - Adding [servletContextInitParams] PropertySource with lowest search precedence
15:22:08.455 [main] DEBUG org.springframework.web.context.support.StandardServletEnvironment - Adding [systemProperties] PropertySource with lowest search precedence
15:22:08.455 [main] DEBUG org.springframework.web.context.support.StandardServletEnvironment - Adding [systemEnvironment] PropertySource with lowest search precedence
15:22:08.455 [main] DEBUG org.springframework.web.context.support.StandardServletEnvironment - Initialized StandardServletEnvironment with PropertySources [servletConfigInitParams,servletContextInitParams,systemProperties,systemEnvironment]
15:22:08.455 [main] INFO org.springframework.mock.web.MockServletContext - Initializing Spring FrameworkServlet ''
15:22:08.455 [main] INFO org.springframework.test.web.servlet.TestDispatcherServlet - FrameworkServlet '': initialization started
15:22:08.457 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Unable to locate MultipartResolver with name 'multipartResolver': no multipart request handling provided
15:22:08.458 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Using LocaleResolver [org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver#267f474e]
15:22:08.458 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Using ThemeResolver [org.springframework.web.servlet.theme.FixedThemeResolver#7a7471ce]
15:22:08.458 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Using RequestToViewNameTranslator [org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator#28276e50]
15:22:08.458 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Using FlashMapManager [org.springframework.web.servlet.support.SessionFlashMapManager#62e70ea3]
15:22:08.458 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Published WebApplicationContext of servlet '' as ServletContext attribute with name [org.springframework.web.servlet.FrameworkServlet.CONTEXT.]
15:22:08.458 [main] INFO org.springframework.test.web.servlet.TestDispatcherServlet - FrameworkServlet '': initialization completed in 3 ms
15:22:08.458 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Servlet '' configured successfully
15:22:08.476 [main] DEBUG groovyx.net.http.RESTClient - POST http://localhost:603/toolbox/exec
15:22:08.728 [main] DEBUG org.apache.http.impl.conn.BasicClientConnectionManager - Get connection for route {}->http://localhost:603
15:22:08.742 [main] DEBUG org.apache.http.impl.conn.DefaultClientConnectionOperator - Connecting to localhost:603
15:22:09.744 [main] DEBUG org.apache.http.impl.conn.DefaultClientConnectionOperator - Connect to localhost:603 timed out. Connection will be retried using another IP address
15:22:09.745 [main] DEBUG org.apache.http.impl.conn.DefaultClientConnectionOperator - Connecting to localhost:603
15:22:10.745 [main] DEBUG org.apache.http.impl.conn.DefaultClientConnection - Connection org.apache.http.impl.conn.DefaultClientConnection#21362712 closed
15:22:10.745 [main] DEBUG org.apache.http.impl.conn.DefaultClientConnection - Connection org.apache.http.impl.conn.DefaultClientConnection#21362712 shut down
15:22:10.746 [main] DEBUG org.apache.http.impl.conn.BasicClientConnectionManager - Releasing connection org.apache.http.impl.conn.ManagedClientConnectionImpl#27eb3298
EXCEPTION
java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:120)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:179)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:328)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:612)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:447)
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:884)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
at groovyx.net.http.HTTPBuilder.doRequest(HTTPBuilder.java:476)
at groovyx.net.http.HTTPBuilder.doRequest(HTTPBuilder.java:441)
at groovyx.net.http.HTTPBuilder.request(HTTPBuilder.java:373)
at com.xetra11.toolbox.components.executor.RestHandlerTest.ExecuteToolTest(RestHandlerTest.groovy:26)
Process finished with exit code -1
This is what you need
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class RestHandlerTest extends Specification {
#Autowired
TestRestTemplate testRestTemplate
And then you use testRestTemplate instead of client. You also need to add spock-spring dependency.
I have a SpringBatch project where I want to catch an exception thrown when the application cannot find the datasource. I've already by-passed this, so it will use 'in memory DAO objects' instead of tables.. but it still throws an exception when datasource is not found.
I want to catch that exception and throw my own error code, but I have no idea where the try/catch block must be placed.
Here is a piece of the error log:
2016-11-24 09:25:36.171 INFO 36770 --- [main] c.d.d.e.config.ReaderConfiguration : Configuring FlatFileItemReader for [MAP]
2016-11-24 09:25:51.664 ERROR 36770 --- [main] o.a.tomcat.jdbc.pool.ConnectionPool : Unable to create initial connections of pool.
com.microsoft.sqlserver.jdbc.SQLServerException: The TCP/IP connection to the host [***], port 1433 has failed. Error: "null. Verify the connection properties. Make sure that an instance of SQL Server is running on the host and accepting TCP/IP connections at the port. Make sure that TCP connections to the port are not blocked by a firewall.".
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:190) ~[sqljdbc4.jar:na]
This is overridden to bypass table creation. Also, I use two datasources and this class needed to be here anyway.
#Component
public class MyBatchConfigurer extends DefaultBatchConfigurer {
//Spring batch needs this in order to allow to use more than one datasource
#Override
public JobRepository createJobRepository() throws Exception {
return new MapJobRepositoryFactoryBean().getObject();
}
}
To be noted that I even tried to place try/catch on "the main" method.. and it still throws the exception above.. and then gets to the breakpoint inside catch.
Also, I tried creating the datasource manually.. but to no avail. Even more, ApplicationEvent doesn't seem to work either.
This is a log where datasource is found:
2016-10-25 16:05:13 [main] INFO c.d.d.e.config.CompanyConfiguration - Configure FlatFileItemReader for [IW]
2016-10-25 16:05:13 [main] INFO o.s.jdbc.datasource.init.ScriptUtils - Executing SQL script from class path resource [org/springframework/batch/core/schema-sqlserver.sql]
2016-10-25 16:05:13 [main] INFO o.s.jdbc.datasource.init.ScriptUtils - Executed SQL script from class path resource [org/springframework/batch/core/schema-sqlserver.sql] in 49 ms.
2016-10-25 16:05:13 [main] INFO o.s.b.f.config.PropertiesFactoryBean - Loading properties file from URL [jar:file:/home/etl/d-d/d-e-1.0.4-SNAPSHOT.jar!/lib/spring-integration-core-4.2.5.RELEASE.jar!/META-INF/spring.integration.default.properties]
Is there anyway I can know in my program, the full path of file loaded through #PropertySource annotation of Spring.
I need it to show in logs so that one can know which property file is being used in the application
This information is logged already by StandardServletEnvironment. You can set log level to DEBUG for org.springframework.web.context.support.StandardServletEnvironment class to show details in your logs.
If you use spring-boot you can simply add following line into your application.properties file.
logging.level.org.springframework.web.context.support.StandardServletEnvironment = DEBUG
Below seems to be working, though I am not sure if the instance is always of type ConfigurableEnvironment
#Component
public class MyListener implements ApplicationListener<ContextRefreshedEvent>{
#Autowired
private Environment env;
private static final Logger log = LoggerFactory.getLogger(MyListener.class);
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if(env instanceof ConfigurableEnvironment){
MutablePropertySources propertySources = ((ConfigurableEnvironment)env).getPropertySources();
for(PropertySource ps : propertySources){
log.info(ps.getName()); //if only file based needed then check if instanceof ResourcePropertySource
}
}
}
}
Edit: don't really need all this. As already answered by Selim, enabling the proper logs does the trick
log4j.logger.org.springframework.core.env.MutablePropertySources=DEBUG
in current ('21) versions of Spring Boot, neither of the two above suggestions for the logging level seem to work. moreover - if the file is actually NOT loaded, because it is NOT found or for whatever other reason, nothing is printed anyway.
at the moment when i have my ROOT logger set to DEBUG (logging.level.root=DEBUG in application.properties), the only thing I see in the log file, when the file is loaded correctly and the #Value annotated property is resolved successfully is:
2021-07-23 11:06:10.299 DEBUG 16776 --- [ restartedMain]
o.s.b.f.s.DefaultListableBeanFactory : Creating shared instance of
singleton bean 'bahblahService'
2021-07-23 11:06:10.302 DEBUG 16776 --- [ restartedMain]
o.s.c.e.PropertySourcesPropertyResolver : Found key
'blahblah.username' in PropertySource 'class path
resource [custom-local.properties]' with value of type String
Is it possible to have beans of imported java based configurations be created with prototype scope?
What I mean is that if I have the following example code:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(
SpringTopLevelConfig.class);
for (int i = 0; i < 2; i++) {
System.out.println(applicationContext.getBean(Student.class));
}
Where
public class Notebook {
static int idCounter = 1;
private final int id;
#Override
public String toString() {
return "Notebook{" +
"id=" + id +
'}';
}
public Notebook() {
id = idCounter++;
}
}
public class Student {
private final Notebook notebook;
#Override
public String toString() {
return "Student{" +
"notebook=" + notebook +
'}';
}
public Student(Notebook notebook) {
this.notebook = notebook;
}
}
And spring Config is :
#Configuration
public class SpringTopLevelConfig {
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Bean
Notebook notebook(){
return new Notebook();
}
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Bean
Student student(){
return new Student(notebook());
}
}
As expected each student gets its own notebook:
Student{notebook=Notebook{id=1}}
Student{notebook=Notebook{id=2}}
However if I try to split up the configuration across multiple classes all of the examples I have found suggest using #Autowire to accomplish this:
#Configuration
#Import(SpringConfigSecondLevel.class)
public class SpringTopLevelConfig {
#Autowired
Notebook notebook;
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Bean
Student student(){
return new Student(notebook);
}
}
#Configuration
public class SpringConfigSecondLevel {
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Bean
Notebook notebook(){
return new Notebook();
}
}
However now the students end up sharing one notebook which is not the behaviour I am trying to achieve.
Student{notebook=Notebook{id=1}}
Student{notebook=Notebook{id=1}}
Is there a spring way to achieve SCOPE_PROTOTYPE behaviour with split configuration classes or will I need to create a NotebookFactory bean to save the students from fighting each other over the same notebook?
The two config file approach did not have the expected result, because you autowire the notebook inside SpringTopLevelConfig class. That notebook instance will be created once, and used from all other student objects, since when you create the student, inside the student constructor you pass that notebook instance instead of the notebook() bean method. You can pass the notebook() bean method inside the student constructor by autowiring the whole config class, so that you can call it:
#Configuration
#Import(SpringConfigSecondLevel.class)
public class SpringTopLevelConfig {
#Autowired SpringConfigSecondLevel springConfigSecondLevel;
#Scope("prototype")
#Bean
Student student(){
return new Student(springConfigSecondLevel.notebook());
}
}
#Configuration
public class SpringConfigSecondLevel {
#Scope("prototype")
#Bean
Notebook notebook(){
return new Notebook();
}
}
Since the Notebook instance is #Autowired it will be created once while creating the springTopLevelConfig singleton bean. This is evident from spring debug level logs
14:59:15.631 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'springTopLevelConfig'
14:59:15.631 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'springTopLevelConfig'
14:59:15.639 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Registered injected element on class [com.example.spring.prototype_level.SpringTopLevelConfig$$EnhancerBySpringCGLIB$$2fffb2e0]: AutowiredFieldElement for com.example.spring.prototype_level.Notebook com.example.spring.prototype_level.SpringTopLevelConfig.notebook
14:59:15.640 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'springTopLevelConfig' to allow for resolving potential circular references
14:59:15.673 [main] DEBUG o.s.b.f.annotation.InjectionMetadata - Processing injected method of bean 'springTopLevelConfig': AutowiredFieldElement for com.example.spring.prototype_level.Notebook com.example.spring.prototype_level.SpringTopLevelConfig.notebook
14:59:15.682 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'notebook'
14:59:15.682 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:59:15.682 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:59:15.684 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'com.example.spring.prototype_level.SpringConfigSecondLevel' to allow for resolving potential circular references
14:59:15.698 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:59:15.731 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'notebook'
14:59:15.732 [main] DEBUG o.s.b.f.a.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'springTopLevelConfig' to bean named 'notebook'
14:59:15.733 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'springTopLevelConfig'
14:59:15.733 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor'
14:59:15.733 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor'
14:59:15.733 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:59:15.736 [main] DEBUG o.s.c.a.AnnotationConfigApplicationContext - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor#391663bd]
14:59:15.736 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
14:59:15.739 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties]
14:59:15.739 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment]
14:59:15.740 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null]
14:59:15.740 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'student'
14:59:15.740 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'springTopLevelConfig'
14:59:15.752 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'student'
Student{notebook=Notebook{id=1}}
14:59:15.753 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'student'
14:59:15.753 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'springTopLevelConfig'
14:59:15.753 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'student'
Student{notebook=Notebook{id=1}}
An alternative would be to inject the Notebook instance using applicationContext as below
#Configuration
#Import(SpringConfigSecondLevel.class)
public class SpringTopLevelConfig{
#Autowired
private ApplicationContext applicationContext;
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Bean
Student student(){
return new Student(applicationContext.getBean(Notebook.class));
}
}
Now spring will create the Notebook instance every time you create a Student instance. The spring logs too say so
14:55:51.255 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'springTopLevelConfig'
14:55:51.255 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'springTopLevelConfig'
14:55:51.258 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'springTopLevelConfig' to allow for resolving potential circular references
14:55:51.284 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'springTopLevelConfig'
14:55:51.285 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor'
14:55:51.285 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor'
14:55:51.285 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:55:51.285 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:55:51.287 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'com.example.spring.prototype_level.SpringConfigSecondLevel' to allow for resolving potential circular references
14:55:51.292 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:55:51.295 [main] DEBUG o.s.c.a.AnnotationConfigApplicationContext - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor#1396a464]
14:55:51.297 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
14:55:51.300 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties]
14:55:51.301 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment]
14:55:51.302 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null]
14:55:51.302 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'student'
14:55:51.305 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'springTopLevelConfig'
14:55:51.342 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'notebook'
14:55:51.342 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:55:51.352 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'notebook'
14:55:51.354 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'student'
Student{notebook=Notebook{id=1}}
14:55:51.355 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'student'
14:55:51.355 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'springTopLevelConfig'
14:55:51.355 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'notebook'
14:55:51.355 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'com.example.spring.prototype_level.SpringConfigSecondLevel'
14:55:51.355 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'notebook'
14:55:51.355 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'student'
Student{notebook=Notebook{id=2}}
Others have explained why your first attempt did not work. I would only suggest a solution that does not require using an #Autowired field.
#Configuration
#Import(SpringConfigSecondLevel.class)
public class SpringTopLevelConfig {
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Bean
public Student student(Notebook notebook) {
return new Student(notebook);
}
}
If you simply add a method parameter of type Notebook, the Spring container will supply you with a new instance automatically.