Spring + 2X
Spring + 2X
I have the project working on sfs 1.6 with spring framework on server-side.
Now I want to move it on 2X version. Unfortunately I have the problem with classpath:
"org.springframework.beans.factory.NoSuchBeanDefinitionException"
I just put all my java-classes into .jar file and create new extension for it.
"spring-config.xml" there is in kernel folder.
Thanks for help!
Now I want to move it on 2X version. Unfortunately I have the problem with classpath:
"org.springframework.beans.factory.NoSuchBeanDefinitionException"
I just put all my java-classes into .jar file and create new extension for it.
"spring-config.xml" there is in kernel folder.
Thanks for help!
Spring SFS2
Hi Does anyone have an example if this working? I'm pretty new to Spring but based on my current understanding an ApplicationContext needs to be constructed in order to load in the spring configuration from an external xml file in order to get Spring working generally but I was wondering how to do this with SFS2X?
I have tried by placing the following code in the init method of one of my extensions where applicationContext.xml is my spring config file and is on the class path (I have put it in the SFS2X dir, the SFS2x/lib dir and a few other places.
Whenever I try to launch he server with this code in the extension I get the error shown below where it seems to attempt to do something but then the boot process stops and the server does not start. I'm probably doing something totally incorrect but would really appreciate if anyone had any ideas how I could get Spring working wuth SFS2x
21 Dec 2010 09:15:09,551 INFO [main] entities.managers.SFSZoneManager - Creating room: (default) Limbo
21 Dec 2010 09:15:09,557 WARN [main] entities.managers.SFSZoneManager - RoomSetting literal not found:
21 Dec 2010 09:15:09,560 INFO [main] v2.api.SFSApi - Room created: [ Room: Limbo, Id: 0, Group: default, isGame: false ]
21 Dec 2010 09:15:09,560 INFO [main] entities.managers.SFSZoneManager - Creating room: (default) User
21 Dec 2010 09:15:09,561 WARN [main] entities.managers.SFSZoneManager - RoomSetting literal not found:
21 Dec 2010 09:15:09,561 INFO [main] v2.api.SFSApi - Room created: [ Room: User, Id: 1, Group: default, isGame: false ]
21 Dec 2010 09:15:09,573 DEBUG [main] user.room.UserRoomExtension - Initialised!
21 Dec 2010 09:15:09,583 DEBUG [main] user.buddylist.BuddyListPersister - BuddyListPersister initialized.
21 Dec 2010 09:15:09,586 DEBUG [main] secure.zone.SecureZoneExtension - initialise SecureZoneExtension
21 Dec 2010 09:15:09,618 INFO [main] context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@451ef443: startup date [Tue Dec 21 09:15:09 GMT 2010]; root of context hierarchy
21 Dec 2010 09:15:09,649 INFO [Thread-2] entities.managers.SFSZoneManager - BuddyList saveAll...
21 Dec 2010 09:15:09,649 WARN [SFS2X ShutdownHook] v2.core.SFSShutdownHook - SFS2X is shutting down. The process may take a few seconds...
21 Dec 2010 09:15:09,671 INFO [Thread-3] entities.managers.SFSBannedUserManager - BanUser data saved.
I have tried by placing the following code in the init method of one of my extensions where applicationContext.xml is my spring config file and is on the class path (I have put it in the SFS2X dir, the SFS2x/lib dir and a few other places.
Code: Select all
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Whenever I try to launch he server with this code in the extension I get the error shown below where it seems to attempt to do something but then the boot process stops and the server does not start. I'm probably doing something totally incorrect but would really appreciate if anyone had any ideas how I could get Spring working wuth SFS2x
21 Dec 2010 09:15:09,551 INFO [main] entities.managers.SFSZoneManager - Creating room: (default) Limbo
21 Dec 2010 09:15:09,557 WARN [main] entities.managers.SFSZoneManager - RoomSetting literal not found:
21 Dec 2010 09:15:09,560 INFO [main] v2.api.SFSApi - Room created: [ Room: Limbo, Id: 0, Group: default, isGame: false ]
21 Dec 2010 09:15:09,560 INFO [main] entities.managers.SFSZoneManager - Creating room: (default) User
21 Dec 2010 09:15:09,561 WARN [main] entities.managers.SFSZoneManager - RoomSetting literal not found:
21 Dec 2010 09:15:09,561 INFO [main] v2.api.SFSApi - Room created: [ Room: User, Id: 1, Group: default, isGame: false ]
21 Dec 2010 09:15:09,573 DEBUG [main] user.room.UserRoomExtension - Initialised!
21 Dec 2010 09:15:09,583 DEBUG [main] user.buddylist.BuddyListPersister - BuddyListPersister initialized.
21 Dec 2010 09:15:09,586 DEBUG [main] secure.zone.SecureZoneExtension - initialise SecureZoneExtension
21 Dec 2010 09:15:09,618 INFO [main] context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@451ef443: startup date [Tue Dec 21 09:15:09 GMT 2010]; root of context hierarchy
21 Dec 2010 09:15:09,649 INFO [Thread-2] entities.managers.SFSZoneManager - BuddyList saveAll...
21 Dec 2010 09:15:09,649 WARN [SFS2X ShutdownHook] v2.core.SFSShutdownHook - SFS2X is shutting down. The process may take a few seconds...
21 Dec 2010 09:15:09,671 INFO [Thread-3] entities.managers.SFSBannedUserManager - BanUser data saved.
Seems like something (Spring?) is quitting the application
In fact the last two log messages are exactly the SFS2X Shutdown hook running, right before the JVM is tore down.
I am no Spring expert but I guess there should be some Spring logs somewhere showing some more details.
Final note: the xml config file should go in the SFS2X root folder, the lib/ folder is not exactly in the classpath. Only the jar files contained in it are. (because we use the Java6 wildcard notation)
In fact the last two log messages are exactly the SFS2X Shutdown hook running, right before the JVM is tore down.
I am no Spring expert but I guess there should be some Spring logs somewhere showing some more details.
Final note: the xml config file should go in the SFS2X root folder, the lib/ folder is not exactly in the classpath. Only the jar files contained in it are. (because we use the Java6 wildcard notation)
Hi Silvertip
I've managed to get SFS working with Spring, although I'm not sure if our approach will satisfy your requirements, I can run you through it in case it helps.
Firstly we have our project split into Business Logic Modules and Extensions, a BLM may be used by multiple extensions and as a result resides in the extensions/__lib__ and as you know extension have their own directory e.g. extensions/myExtension. The reason for separating out the business logic is two fold. Firstly it means that the core application is insulated from any changes in smartfox (e.g. when we go from SFS2 to SFS3 for example business logic modules don't care, the only changes will be in the extensions). Secondly in order to get Spring to work I have found that you need to have your jars in the __lib__ directory due to the way the classpath works in SFS.
You will be able to see this if you add a line to the log4j.properties file to trace out the spring debug (log4j.category.org.springframework=DEBUG,consoleAppender,fileAppender) when you try and load your applicationContext file. What this means is that classes in the extension/myExtension jar are not able to use spring instrumentation via annotations such as @Autowired as they never get scanned when the applicationContext loads. They way I have the extensions using the Business Logic modules is to have a singleton that performs the initialisation of the applicationContext upon created and then provides a couple of utility methods to allow the extensions to get at the beans. I have found this works well but I'm open to suggestions if anyone has found a better way to do this. So as way of an example I have something like this in a common project that all extensions can access:
Then I have let's say an extension to allow users to manage their account, with a request handler which handles requests to update their account details which would look something like:
All the extension handler does is extract the details the user is sending from the params object then delgates it off to the service to do the actual business logic work, writing to the db, etc. The UserService business logic module would look something like:
This approach might not suite what you are trying to do and there may be a better way but that's what I had to do to get it working. Hope it helps!
I've managed to get SFS working with Spring, although I'm not sure if our approach will satisfy your requirements, I can run you through it in case it helps.
Firstly we have our project split into Business Logic Modules and Extensions, a BLM may be used by multiple extensions and as a result resides in the extensions/__lib__ and as you know extension have their own directory e.g. extensions/myExtension. The reason for separating out the business logic is two fold. Firstly it means that the core application is insulated from any changes in smartfox (e.g. when we go from SFS2 to SFS3 for example business logic modules don't care, the only changes will be in the extensions). Secondly in order to get Spring to work I have found that you need to have your jars in the __lib__ directory due to the way the classpath works in SFS.
You will be able to see this if you add a line to the log4j.properties file to trace out the spring debug (log4j.category.org.springframework=DEBUG,consoleAppender,fileAppender) when you try and load your applicationContext file. What this means is that classes in the extension/myExtension jar are not able to use spring instrumentation via annotations such as @Autowired as they never get scanned when the applicationContext loads. They way I have the extensions using the Business Logic modules is to have a singleton that performs the initialisation of the applicationContext upon created and then provides a couple of utility methods to allow the extensions to get at the beans. I have found this works well but I'm open to suggestions if anyone has found a better way to do this. So as way of an example I have something like this in a common project that all extensions can access:
Code: Select all
private static ContextUtil instance = new ContextUtil();
Logger log = Logger.getLogger(this.getClass());
private ApplicationContext context;
private ContextUtil(){
log.debug("Loading ContextUtil");
try{
context = new FileSystemXmlApplicationContext(new String[] {"config/applicationContext.xml"}, true);
}catch(Exception e){
log.error("Exception in context util",e);
}
}
public static ContextUtil instance(){
return instance;
}
public Object getService(String serviceName){
return context.getBean(serviceName);
}
Then I have let's say an extension to allow users to manage their account, with a request handler which handles requests to update their account details which would look something like:
Code: Select all
//get a reference to the application context utility singleton
ContextUtil contextUtil = ContextUtil.instance();
//get a reference to my service implementation
IUserService userService = IUserService)contextUtil.getService(USER_SERVICE);
@Override
public void handleClientRequest(User user, ISFSObject params) {
ISFSObject response = SFSObject.newInstance();
//delegate to the service to do the update
try{
userService.updateUserDetails([get the relevant params from the params object]);
response.putShort(Constants.RESPONSE_PARAMETER, RESPONSE_OK);
}catch(Exception se){
log.error("Solidifcation Exception",se);
response.putShort(Constants.RESPONSE_PARAMETER, Constants.RESPONSE_ERROR);
}
send(ACCOUNT_UPDATE,response,user);
}
All the extension handler does is extract the details the user is sending from the params object then delgates it off to the service to do the actual business logic work, writing to the db, etc. The UserService business logic module would look something like:
Code: Select all
private Logger log = Logger.getLogger(this.getClass());
@Autowired
private IUserDao userDao;
public void updateUserDetails(UserDetails userDetails){
validateUserDetails(userDetails);
//do any other BLogic
//svae to the database
userDao.save(userDetails);
}
This approach might not suite what you are trying to do and there may be a better way but that's what I had to do to get it working. Hope it helps!
small improvement suggestion, if you change getService method with generics, you do not have to cast returned object
for example:
or
for example:
Code: Select all
public <T> T getService(Class<T> serviceClass){
return context.getBean(serviceClass);
}
or
Code: Select all
public <T> T getService(String serviceName,Class<T> serviceClass){
return context.getBean(serviceName,serviceClass );
}
I realize this is an old thread, but to help future generations, this code works for me:
All jars are deployed to the myExtension/ directory, and the spring configuration is in my extension's jar.
Code: Select all
ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
ClassLoader extensionLoader = getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(extensionLoader);
context = new GenericXmlApplicationContext(new ClassPathResource("/META-INF/spring/MyExtension-context.xml", extensionLoader));
Thread.currentThread().setContextClassLoader(origLoader);
All jars are deployed to the myExtension/ directory, and the spring configuration is in my extension's jar.
-
- Posts: 34
- Joined: 06 Feb 2012, 09:12
harlanji wrote:I realize this is an old thread, but to help future generations, this code works for me:Code: Select all
ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
ClassLoader extensionLoader = getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(extensionLoader);
context = new GenericXmlApplicationContext(new ClassPathResource("/META-INF/spring/MyExtension-context.xml", extensionLoader));
Thread.currentThread().setContextClassLoader(origLoader);
All jars are deployed to the myExtension/ directory, and the spring configuration is in my extension's jar.
Thank you for your answer,this method works fine.
But notice that when export your project to jar file using eclipse,make sure select the "Add directory entries",otherwise the annotations and bean definitions will not be scanned when the context is initialized!
Now I have integrate spring+hibernate+sfs2x, and all work fine!
Hey chenjie19891104:
I have since changed this to have the following code:
I think this is more elegant because we don't have to mess with the context class loader. ServiceAdapter is just a class in the same .jar as my extension, and I could have easily have used MyExtension.class.
The last line just makes Spring wire up my ServiceAdapter class (could easily be extension also).
Cheers.
I have since changed this to have the following code:
Code: Select all
private void initSpringContext() {
context = new GenericXmlApplicationContext();
context.setClassLoader(ServiceAdapter.class.getClassLoader());
context.load("classpath:/META-INF/spring/service-context.xml");
context.refresh();
context.getAutowireCapableBeanFactory().autowireBean(this);
}
I think this is more elegant because we don't have to mess with the context class loader. ServiceAdapter is just a class in the same .jar as my extension, and I could have easily have used MyExtension.class.
The last line just makes Spring wire up my ServiceAdapter class (could easily be extension also).
Cheers.
Who is online
Users browsing this forum: Baidu [Spider], Stevenor and 114 guests