I have a server application. Now I'm using Spring not only to inject dependencies, but also to config my application. Something like this:
<bean id="server" class="foo.bar.Server">
<property name="host" value="${config.host}"/>
<property name="someBean">
<ref bean="someBean"/>
</property>
</bean>
My colleague sad that configuring application in Spring is not obvious and we should avoid this. I see logic in his words, because Spring is for dependence injection and server port is not dependency, isn't it? But for me configuring application is Spring is very convenient and obvious. Is my colleague right?
Configuring in Spring is simple, clear and maintainable.
This way you can easily create several instances with different properties.
Related
I've got a Spring Integration flow which uses an inbound gateway to get messages from an IBM MQ queue:
<int-jms:inbound-gateway id="InputGateway"
request-destination="RequestQueue"
request-channel="RequestChannel"
reply-channel="ReplyChannel"
/>
However I'm not capable of assigning security settings. In particular, I need an username, password and userAuthenticationMQCSP = false (for reasons beyond the scope of this post, I won't get into details but my broker will throw a MQRC = 2009 otherwise).
I've followed the IBM guide to connect with jmsTemplate and works just fine. This uses the official Spring boot starter from IBM MQ which will kindly create a connection factory and will autoconfigure it with some defaults from application.properties:
ibm.mq.queueManager=myQMName
ibm.mq.channel=myChannel
ibm.mq.connName=myhostname(myPort)
ibm.mq.user=username
ibm.mq.password=*******
ibm.mq.userAuthenticationMQCSP=false
Now, back to the Spring Integration case. According to the int-jms:inbound-gateway spec, a connectionFactory will be injected to the gateway, by name (attribute: connection-factory) which is set up to be "jmsConnectionFactory" by default
By default, all of the JMS adapters that require a reference to the
ConnectionFactory automatically look for a bean named
jmsConnectionFactory. That is why you do not see a connection-factory
attribute in many of the examples. However, if your JMS
ConnectionFactory has a different bean name, you need to provide that
attribute.
I don't see any way to set up a predictable name for the connection factory that I can plug into the int-jms:inbound-gateway.
Now, taking a different approach, as per this example I've created my connectionFactory with an adecuate name:
<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="transportType" value="1"/>
<property name="queueManager" value="myQMName"/>
<property name="hostName" value="myhostname"/>
<property name="port" value="myPort" />
<property name="channel" value="myChannel"/>
</bean>
But now I need somewhere to put the credentials and the security parameters. Looking at the example above, it looks like I need to plug something like:
<bean id="secureJmsConnectionAdapter" class="**yourpackages.SecureJMSConnectionAdapter**">
<property name="targetConnectionFactory" ref="${jms.mq.connection.factory}" />
<property name="userName" value="${jms.username}"/>
<property name="pwdAlias" value="${jms.alias}"/>
</bean>
However it is unclear to me how to implement this SecureJMSConnectionAdapter.
Additionally, if I set up my own connection factory, I will lose all of MQ boot starter automagic thanks to this annotation on the MQAutoConfiguration class:
#ConditionalOnMissingBean(value=javax.jms.ConnectionFactory.class)
Any ideas on how to put these pieces together?
EDIT: Just to avoid any possible red herrings to anyone, the MQRC2009 was irrelevant to ibm.mq.userAuthenticationMQCSP=false.
Some of my old projects I used a bean like this:
<bean id="jmsQueueConnectionFactory"
class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
<property name="username" value="${jms.username}"/>
<property name="password" value="${jms.alias}"/>
</bean>
Should work well as a wrapper for your com.ibm.mq.jms.MQQueueConnectionFactory, but you have to use this jmsQueueConnectionFactory in the target components.
Although it looks like the mentioned IBM MQ JMS Spring doesn't that for us properly exposing a jmsConnectionFactory bean. You can rely on the default from Spring Integration in this case or use that jmsConnectionFactory explicitly for the connection-factory.
Also with Spring Boot you should consider to go away from XML configuration and give a chance for Spring Integration Java DSL: https://docs.spring.io/spring-integration/docs/5.1.7.RELEASE/reference/html/#java-dsl
I have a Spring-Boot application that just have a simple rest controller. On this controller, I added the jmx annotations #ManagedResource and #ManagedOperation and it is working fine. It is correctly exposed in Jmx.
This application depends on a "global-commons" library to share many basic functionality to all of our modules.
But if I add the same annotations to a class in this library, it is ignored!
And before you ask, yes the library is imported with the latest change.
There is no error or warning message in the logs.
I am configuring all my beans using an xml file. Both classes are beans defined in the same file.
One is a #RestController. The other one is a simple utility class.
Any idea?
Make sure the classes from the global-commons library as managed by Spring. As long as none of the classes in the library are managed by Spring, the annotions don't have any effect.
I found the problems:
The bean that was not working was defined as an "inner" bean:
<bean id="imMetrics" class="com.imetrik.global.common.metrics.ImGlobalMetrics" init-method="init">
...
<property name="reporterList">
<util:list>
<bean id="jmxReporter" class="com.imetrik.global.common.metrics.reporters.ImJmxReporter">
<property name="registryId" value="metricRegistry1"/>
<property name="durationUnit" value="SECONDS"/>
<property name="rateUnit" value="SECONDS"/>
<property name="domain" value="com.imetrik.global.metric"/>
</bean>
</util:list>
</property>
</bean>
The annotated beans is "jmxReporter".
But if I put it outside as a normal "first level" bean and use a reference instead, it is working.
But it is annoying! Is there a way to make it work even as a inner beans?
I have a spring mvc app that I want to refactor out, speficially removing the spring related code and wiring.
It is a simple spring mvc at this point, so the key things I have to do our dependancy injection.
My application.xml has wirings for my Dao objects, injecting the datasource into my Dao objects.
How can I use a spring agnostic DI now? What do I have to change? I want to use guice unless you guys recommend otherwise
application.xml:
<bean id="userDao" class="com.blah.dao.UserDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
What do you suggest I use to setup my datasource and connection pooling now?
The actual page/url mapping is specific to if I choose servlets or a jetty handler.
You can use the standard annotation #Inject for dependency injection. Both Spring and Guice support it.
I read about using
<context:component-scan base-package="tld.mydomain.business">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
and annotate my service beans with #Service("myService"), and thought great, I'll do that, since I'm already doing that with my controllers. My usual service bean configuration looks like
<bean id="userService" parent="txProxyTemplate">
<property name="target">
<bean class="tld.mydomain.business.UserServiceImpl"/>
</property>
<property name="proxyInterfaces" value="tld.mydomain.business.UserService"/>
</bean>
so now that I generate them, how do I wrap them in a Hibernate proxy such as TransactionProxyFactoryBean? Or is there a better way to do that as well?
I have not yet gone all the way and used #Repository as well, is that required?
Cheers
Nik
Using TransactionProxyFactoryBean is not encouraged in modern Spring applications, although it still works. The typical approach nowadays is to annotate classes with #Transactional, and then stick this element in your application context file:
<tx:annotation-driven transaction-manager="txManager"/>
This and other strategies are discussed in great depth in the reference document, and there's even a side note about TransactionProxyFactoryBean.
There's no need for
<context:include-filter type="annotation"expression="org.springframework.stereotype.Service"/>
Spring will register #Service, #Repository, #Component... once they are found in the base package.
Like #Rob said either use #Transactional or <aop:config>...</aop:config> to handle your transactions at the service level.
If you have two different resources that need to be in the same transaction, then you will need to use JTA. See my answer to an earlier question here. Your config would need to look something like:
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="appserver/jndi/path" />
</bean>
Where appserver/jndi/path would need to be replaced with the JNDI path of the JTA transaction manager that comes with your application server (although you can use a standalone JTA transaction manager such as JOTM as well). Typical paths as mentioned in the 2.5.x API are:
"java:comp/UserTransaction" for Resin 2.x, Oracle OC4J (Orion), JOnAS (JOTM), BEA WebLogic
"java:comp/TransactionManager" for Resin 3.x
"java:appserver/TransactionManager" for GlassFish
"java:pm/TransactionManager" for Borland Enterprise Server and Sun Application Server (Sun ONE 7 and later)
"java:/TransactionManager" for JBoss Application Server
I am trying to use Log4j as part of the Spring Framework,
as far as i understand through the use of a an appropriate bean
the system is supposed to map a singleton instance accessible in the code
while mapping the logging depth automatically to the class
Similar to the normal use of Log4J as in
Logger log = Logger.getLogger(getClass());
i have been using the following Spring bean definition
<bean id="log4jInitialization"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"
value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>conf\log4j.xml</value>
</list>
</property>
</bean>
But i am unable to map this bean to a specific member in a given class
nor am i able to use it through #autowired
Please let me know if there are any better ways to integrate Log4j and Spring
Best Regards
Mark
The short answer to your question is that log4j is not DI friendly.
The Log4jConfigurer.initLogging() method has a void return value, so there's nothing to inject. The idea is that you call that method, which bootstraps log4j, and then you use the Log4j API as usual (using Logger.getLogger(getClass())).
You generally wouldn't configure Log4jConfigurer as a Spring bean, though, but more usually you'd invoke it directly from your own code during application startup.
If this is a webapp, then Spring provides alternatives to Log4jConfigurer that are better suited to that environment (Log4jWebConfigurer, Log4jConfigListener).
Incidentally, 2 years ago I filed a feature request to allow loggers to be autowired, and it's finally been marked as fix for Spring 3.1. Horray.