I am using jboss 5.1.0.GA (build: SVNTag=JBoss_5_1_0_GA date=200905221634). And need to get business interface of the bean. That is necessary for transaction management.
So I have:
#Local
public interface MyBeanInterface {
void transactionalMethod();
}
#Stateless
public class MyBean implements MyBeanInterface {
#Resource
private SessionContext context;
private int aState;
public void someMethod() {
aState = 42;
context.getBusinessObject(MyBeanInterface.class).transactionalMethod();
}
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void transactionalMethod() {
System.out.println(aState); // 0!!!!!
}
}
For some reason I do not get the same bean, but new bean is created. That is disastrous as transactionalMethod needs the state variable value to execute correctly.
What am I doing wrong, or that is a bug of jboss? By the way there is a bug which affects ability to get business object via bean's class: https://issues.jboss.org/browse/EJBTHREE-2126. Not sure however if it relates to my issue.
The best solution is this:
#Stateless
public class MyBean implements MyBeanInterface {
#Resource private TransactionManager tm;
private int aState;
public void someMethod() {
aState = 42;
Transaction transaction = tm.suspend();
transactionalMethod();
tm.resume(transaction);
}
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void transactionalMethod() {
System.out.println(aState); // 0!!!!!
}
}
When you call a published interface method from the same istance, passing by ejb context, the resource is:
If it is #Stateless, a new instance is created.
If it is #Stateful, a new session is created for the first call, then other call are same as #Singleton.
If it is #Singleton, the caller waits for the resource to be freed, in case it calls itself, a deadlock is created. If the method is annotated with #Read, calling yourself does not create any deadlocks.
I don't have time to see if the syntax is perfect but you could try:
InitialContext jndiContext = new InitialContext();
Object ref = jndiContext.lookup("projname/MyBeanInterface/local");
MyBeanInterfaceLocal m = (MyBeanInterfaceLocal) ref;
However I saw that you have a SessionContext field, so maybe for you the code should be a little bit different. Maybe it would be:
Object ref = SessionContext.lookup("projname/MyBeanInterface/local");
MyBeanInterfaceLocal m = (MyBeanInterfaceLocal) ref;
Let me know if this helps!
Related
I'm new to spring and doing some study about proxyMode=ScopedProxyMode.TARGET_CLASS. I wrote a simple project to test this with singleton and prototype bean. But it prints a new prototype bean instance when I print the object.
public class SimplePrototypeBean {
private String name;
//getter setters.
}
Singleton bean
public class SimpleBean {
#Autowired
SimplePrototypeBean prototypeBean;
public void setTextToPrototypeBean(String name) {
System.out.println("before set > " + prototypeBean);
prototypeBean.setText(name);
System.out.println("after set > " + prototypeBean);
}
public String getTextFromPrototypeBean() {
return prototypeBean.getText();
}
}
Config class.
#Configuration
public class AppConfig {
#Bean
SimpleBean getTheBean() {
return new SimpleBean();
}
#Bean
#Scope(value = "prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
public SimplePrototypeBean getPrototypeBean(){
return new SimplePrototypeBean();
}
}
Unit test
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = AppConfig.class)
public class SimpleConfigTest {
#Test
public void simpleTestAppConfig() {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
for (String beanName : ctx.getBeanDefinitionNames()) {
System.out.println("Bean " + beanName);
}
SimpleBean simpleBean1 = (SimpleBean) ctx.getBean("getTheBean");
SimpleBean simpleBean2 = (SimpleBean) ctx.getBean("getTheBean");
simpleBean1.setTextToPrototypeBean("XXXX");
simpleBean2.setTextToPrototypeBean("YYYY");
System.out.println(simpleBean1.getTextFromPrototypeBean());
System.out.println(simpleBean2.getTextFromPrototypeBean());
System.out.println(simpleBean2.getPrototypeBean());
}
}
Output
Bean org.springframework.context.annotation.internalAutowiredAnnotationProcessor
Bean org.springframework.context.annotation.internalCommonAnnotationProcessor
Bean org.springframework.context.event.internalEventListenerProcessor
Bean org.springframework.context.event.internalEventListenerFactory
Bean appConfig
Bean getTheBean
Bean scopedTarget.getPrototypeBean
Bean getPrototypeBean
springCertification.com.DTO.SimpleBean#762ef0ea
springCertification.com.DTO.SimpleBean#762ef0ea
before set > springCertification.com.DTO.SimplePrototypeBean#2f465398
after set > springCertification.com.DTO.SimplePrototypeBean#610f7aa
before set > springCertification.com.DTO.SimplePrototypeBean#6a03bcb1
after set > springCertification.com.DTO.SimplePrototypeBean#21b2e768
null
null
springCertification.com.DTO.SimplePrototypeBean#17a7f733
See above output always showing new instance and the value in the text field is null. I'm running only once this app. So I'm expecting only 2 prototype instances will be created as I call simpleBean1 and simpleBean2. Can someone explain to me why this is happening and how to fix it to have only 2 prototype objects where simpleBean1 holds one prototypeBean and simpleBean2 holds another prototypeBean
Intro
Consider the following part of your code:
public class SimpleBean {
#Autowired
SimplePrototypeBean prototypeBean;
}
what do you expect the prototypeBean field to refer to?
Should it always be the same instance of a PrototypeBean?
Or should it enclose the prototype logic somehow?
Prototype means, every time we ask an IoC container for a bean it will return a new instance
When default configuration used (without specifying the proxyMode), the field will appear to us as the same prototype instance
But when you specify TARGET_CLASS or INTERFACES then not the PrototypeBean instance will be injected, but its proxy, (see Scoped beans as dependencies):
That is, you need to inject a proxy object that exposes the same public interface as the scoped object but that can also retrieve the real target object from the relevant scope (such as an HTTP request) and delegate method calls onto the real object.
and when the scope is prototype, then:
every method call on the shared proxy leads to the creation of a new target instance to which the call is then being forwarded.
That is when you call any method, incuding the toString method, on the SimplePrototypeBean bean, Spring creates a new target instance of SimplePrototypeBean underneath to invoke the method on.
Another mcve
You can try the following MCVE to gain the understanding:
#Component
#Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RandomHolder {
private final int random = ThreadLocalRandom.current().nextInt();
public int getRandom() {
return random;
}
}
And the class with main:
#SpringBootApplication
#AllArgsConstructor
public class SoApplication implements ApplicationRunner {
private final RandomHolder randomHolder;
public static void main(String[] args) {
SpringApplication.run(SoApplication.class, args);
}
#Override
public void run(ApplicationArguments args) {
System.out.println("random = " + randomHolder.getRandom());
System.out.println("random = " + randomHolder.getRandom());
}
}
It is a Spring Boot application
RandomHolder is a prototype bean in the IoC container (identical to the way you declared the getPrototypeBean bean)
The RandomHolder has one field which we expect to be the same.
When we run the application returned values from the getRandom method can be different, here is a sample output:
random = 183673952
random = 1192775015
as we now know, the randomHolder refers to a proxy, and when a method is invoked on it, the new target instance of RandomHolder is created and the method is invoked on it.
You can imagine that the proxy looks like this:
public class RandomHolderProxy extends RandomHolder {
private final Supplier<RandomHolder> supplier = RandomHolder::new;
#Override
public int getRandom() {
return supplier.get().getRandom();
}
}
that is, it has an ability to create RandomHolders and invokes methods on new instances of them.
Without proxyMode = ScopedProxyMode.TARGET_CLASS
when we drop the proxyMode argument:
the output is the same
random = 2628323
random = 2628323
Spring won't create a proxy, but will create a new instance every time it requested
If we add another component:
#AllArgsConstructor
#Component
public class ApplicationRunner2 implements ApplicationRunner {
private final RandomHolder randomHolder;
#Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner2: " + randomHolder.getRandom());
System.out.println("ApplicationRunner2: " + randomHolder.getRandom());
}
}
then the output could be:
random = -1884463062
random = -1884463062
ApplicationRunner2: 1972043512
ApplicationRunner2: 1972043512
So I'm expecting only 2 prototype instances will be created as I call simpleBean1 and simpleBean2.
Your expectation is a little bit inexact there, you have as many instances of prototype bean created as many times you have any methods invoked on.
Can someone explain to me why this is happening
I hope, my explanation was clear enough
and how to fix it to have only 2 prototype objects where simpleBean1 holds one prototypeBean and simpleBean2 holds another prototypeBean
The problem here is not in the prototype scope, but in the scope of SimpleBean: it is a singleton, so you have the same instance of SimpleBean when you do:
SimpleBean simpleBean1 = (SimpleBean) ctx.getBean("getTheBean");
just add an assertion to your test method:
SimpleBean simpleBean1 = (SimpleBean) ctx.getBean("getTheBean");
SimpleBean simpleBean2 = (SimpleBean) ctx.getBean("getTheBean");
Assertions.assertSame(simpleBean2, simpleBean1);
it won't fail.
Once again, hope this helps.
I've got a Factory class in Java with some methods which return some Java Bean. All of these Java Beans have some DAO object as fields which are injected with the annotation #EJB. However in every case these DAO are all Null, so I suppose I've a problem with EJB injection. I use WebLogic for deploy. Any suggestions to resolve the issue?
//Factory class
public class Factory extends AbstractFactory {
#Override
public InterfaceService getService() {
return new ClassBean();
}
}
//Bean class
#Stateless(mappedName = "ClassBean")
#LocalBean
public class ClassBean implements IBeanService {
#EJB(beanName = "ClassDAO")
private ClassDAO classDAO;
public List<String> getList() throws ExpectedModelException {
return classDAO.getStringList(); //this one throws NullPointerException
}
Never create Enterprise-Beans using new.
The creation, caching, deletion,... is done by the container.
You must declare ClassDao as #Stateless or #Singleton, ... and the container will create and find it, hopefully if the names are correct.
The Factory is not necessary.
I want to re-create (new Object) a specific bean at Runtime (no restarting the server) upon some DB changes. This is how it looks -
#Component
public class TestClass {
#Autowired
private MyShop myShop; //to be refreshed at runtime bean
#PostConstruct //DB listeners
public void initializeListener() throws Exception {
//...
// code to get listeners config
//...
myShop.setListenersConfig(listenersConfig);
myShop.initialize();
}
public void restartListeners() {
myShop.shutdownListeners();
initializeListener();
}
}
This code does not run as myShop object is created by Spring as Singleton & its context does not get refreshed unless the server is restarted. How to refresh (create a new object) myShop ?
One bad way I can think of is to create new myShop object inside restartListeners() but that does not seem right to me.
In DefaultListableBeanFactory you have public method destroySingleton("beanName")so you can play with it, but you have to be aware that if your autowired your bean it will keep the same instance of the object that has been autowired in the first place, you can try something like this:
#RestController
public class MyRestController {
#Autowired
SampleBean sampleBean;
#Autowired
ApplicationContext context;
#Autowired
DefaultListableBeanFactory beanFactory;
#RequestMapping(value = "/ ")
#ResponseBody
public String showBean() throws Exception {
SampleBean contextBean = (SampleBean) context.getBean("sampleBean");
beanFactory.destroySingleton("sampleBean");
return "Compare beans " + sampleBean + "=="
+ contextBean;
//while sampleBean stays the same contextBean gets recreated in the context
}
}
It is not pretty but shows how you can approach it. If you were dealing with a controller rather than a component class, you could have an injection in method argument and it would also work, because Bean would not be recreated until needed inside the method, at least that's what it looks like. Interesting question would be who else has reference to the old Bean besides the object it has been autowired into in the first place,because it has been removed from the context, I wonder if it still exists or is garbage colected if released it in the controller above, if some other objects in the context had reference to it, above would cause problems.
We have the same use-case. As already mentioned one of the main issues with re-creating a bean during runtime is how to updating the references that have already been injected. This presents the main challenge.
To work around this issue I’ve used Java’s AtomicReference<> class. Instead of injecting the bean directly, I’ve wrapped it as an AtomicReference and then inject that. Because the object wrapped by the AtomicReference can be reset in a thread safe manner, I am able to use this to change the underlying object when a database change is detected. Below is an example config / usage of this pattern:
#Configuration
public class KafkaConfiguration {
private static final String KAFKA_SERVER_LIST = "kafka.server.list";
private static AtomicReference<String> serverList;
#Resource
MyService myService;
#PostConstruct
public void init() {
serverList = new AtomicReference<>(myService.getPropertyValue(KAFKA_SERVER_LIST));
}
// Just a helper method to check if the value for the server list has changed
// Not a big fan of the static usage but needed a way to compare the old / new values
public static boolean isRefreshNeeded() {
MyService service = Registry.getApplicationContext().getBean("myService", MyService.class);
String newServerList = service.getPropertyValue(KAFKA_SERVER_LIST);
// Arguably serverList does not need to be Atomic for this usage as this is executed
// on a single thread
if (!StringUtils.equals(serverList.get(), newServerList)) {
serverList.set(newServerList);
return true;
}
return false;
}
public ProducerFactory<String, String> kafkaProducerFactory() {
Map<String, Object> configProps = new HashMap<>();
configProps.put(ProducerConfig.CLIENT_ID_CONFIG, "...");
// Here we are pulling the value for the serverList that has been set
// see the init() and isRefreshNeeded() methods above
configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, serverList.get());
configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
return new DefaultKafkaProducerFactory<>(configProps);
}
#Bean
#Lazy
public AtomicReference<KafkaTemplate<String, String>> kafkaTemplate() {
KafkaTemplate<String, String> template = new KafkaTemplate<>(kafkaProducerFactory());
AtomicReference<KafkaTemplate<String, String>> ref = new AtomicReference<>(template);
return ref;
}
}
I then inject the bean where needed, e.g.
public MyClass1 {
#Resource
AtomicReference<KafkaTemplate<String, String>> kafkaTemplate;
...
}
public MyClass2 {
#Resource
AtomicReference<KafkaTemplate<String, String>> kafkaTemplate;
...
}
In a separate class I run a scheduler thread that is started when the application context is started. The class looks something like this:
class Manager implements Runnable {
private ScheduledExecutorService scheduler;
public void start() {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(this, 0, 120, TimeUnit.SECONDS);
}
public void stop() {
scheduler.shutdownNow();
}
#Override
public void run() {
try {
if (KafkaConfiguration.isRefreshNeeded()) {
AtomicReference<KafkaTemplate<String, String>> kafkaTemplate =
(AtomicReference<KafkaTemplate<String, String>>) Registry.getApplicationContext().getBean("kafkaTemplate");
// Get new instance here. This will have the new value for the server list
// that was "refreshed"
KafkaConfiguration config = new KafkaConfiguration();
// The set here replaces the wrapped objet in a thread safe manner with the new bean
// and thus all injected instances now use the newly created object
kafkaTemplate.set(config.kafkaTemplate().get());
}
} catch (Exception e){
} finally {
}
}
}
I am still on the fence if this is something I would advocate doing as it does have a slight smell to it. But in limited and careful usage it does provide an alternate approach to the stated use-case. Please be aware that from a Kafka standpoint this code example will leave the old producer open. In reality one would need to properly do a flush() call on the old producer to close it. But that's not what the example is meant to demonstrate.
I have a stateful bean:
#Stateful
public class ClientContext {
private Band band;
public Band getBand() {
return band;
}
public void setBand(Band band) {
this.band = band;
}
}
I have Arquillian test.
public class RequestTest extends Arquillian {
...
#Inject
private ClientContext context;
#Inject
private RequestProcessor processor;
#Test
public void test() {
context.setBand(new Band());
Assert.assertNotNull(context.getBand());
processor.doSomething();
}
}
And Processor code:
#Stateless
#LocalBean
public class RequestProcessor {
...
#Inject
private ClientContext context;
public void doSomething() {
System.out.println(context.getBand());
}
}
I expect RequestProcessor to print out the Band. But actually I get null every time. What can be wrong or may be I don't understand Stateful beans correctly?
You are answering the question yourself, the main basis about the stateful is the keep just one instance per injection, which will live as long the injecting bean does.
so in you need to share a state between beans, you could use a #SessionBean
To clarify, the #Stateful means one instance are going to be created for each place where you are injecting it, this is useful when you need to bind some actions and their state to ONE component, so, if you need to create some info and then share between other classes you need to pick how you want to share it:
#Singleton: There will be just one instance for the entire app.
#SessionScoped: There will by one instance per client.
#Stateless: Will create one if there is no other available, after it will be release for use of other clients
If you are managing views the you can use too:
#RequestScoped: Will create one instance for each request and then destroys it.
#ViewScoped: The bean will remain as long the client keep making updates within the same view
Based on parameters passed to a method, I need to select from one of many Spring beans that are implementations of the same class, but configured with different parameters.
E.g. if user A invokes the method, I need to call dooFoo() on bean A, but if it's user B then I need to call the very same method, only on bean B.
Is there a 'Springier' way of doing this other than sticking all the beans in a map, and deriving a key from the parameters passed to my method?
We face that issue in our project, and we solve it through a Factory-Like class. The client class -the one that needed the bean at runtime- had an instance of the factory, that was injected through Spring:
#Component
public class ImTheClient{
#Autowired
private ImTheFactory factory;
public void doSomething(
Parameters parameters) throws Exception{
IWantThis theInstance = factory.getInstance(parameters);
}
}
So, the IWantThis instance depends on the runtime value of the parameters parameter. The Factory implementation goes like this:
#Component
public class ImTheFactoryImpl implements
ImTheFactory {
#Autowired
private IWantThisBadly anInstance;
#Autowired
private IAlsoWantThis anotherInstance;
#Override
public IWantThis getInstance(Parameters parameters) {
if (parameters.equals(Parameters.THIS)) {
return anInstance;
}
if (parameters.equals(Parameters.THAT)) {
return anotherInstance;
}
return null;
}
}
So, the factory instance holds reference to both of the posible values of the IWantThis class, being IWantThisBadly and IAlsoWantThis both implementations of IWantThis.
Seems like do you want a ServiceLocator using the application context as registry.
See ServiceLocatorFactoryBean support class for creating ServiceLocators mapping keys to bean names without coupling client code to Spring.
Other option is to use a naming convention or annotation based configuration.
for example, assuming that you annotate Services with #ExampleAnnotation("someId"), you can use something like the following Service Locator to retrieve them.
public class AnnotationServiceLocator implements ServiceLocator {
#Autowired
private ApplicationContext context;
private Map<String, Service> services;
public Service getService(String id) {
checkServices();
return services.get(id);
}
private void checkServices() {
if (services == null) {
services = new HashMap<String, Service>();
Map<String, Object> beans = context.getBeansWithAnnotation(ExampleAnnotation.class);
for (Object bean : beans.values()) {
ExampleAnnotation ann = bean.getClass().getAnnotation(ExampleAnnotation.class);
services.put(ann.value(), (Service) bean);
}
}
}
}
Sticking them in a map sounds fine. If it's a Spring-managed map (using util:map, or in Java config), that's better than creating it somewhere else, because then Spring owns all the object references and can manage their lifecycle properly.
If the beans (A, B) you are talking about are SessionScope its no problem at all, they will be selected correctly.
public class BusinessLogic {
private BaseClassOfBeanAandB bean;
public void methodCalledByUserAorB() {
bean.doFoo();
}
}