Liferay Hook work work with Spring+MyBatis(Updated 3 ways now)


In some cases,we need to customize Liferay.In my case,I chose hook to do that.But it Rainto and issue hone to get beans in the service class.
For example:
public class MyOrganizationLocalServiceImpl extends OrganizationLocalServiceWrapper {

	public MyOrganizationLocalServiceImpl(OrganizationLocalService organizationLocalService) {
		super(organizationLocalService);
	}
	
	
	public Organization updateOrganization(long companyId, long organizationId,
			long parentOrganizationId, String name, String type, boolean recursable, long regionId,
			long countryId, int statusId, String comments, boolean site,
			ServiceContext serviceContext) throws PortalException, SystemException {

//...more
This is my own service class,I have to get the beans which will use to connect the database and do some operation.Because Organization LocarviceWrapper doesn't have default constructor、 we can't ask Spring to initialize the class fors.That means we can't use Costructor setting injection in the class. 
Actualy,when you deploy the project,tomcat will read web.xml,then tomcat will initialize beans for use if we do settings like this:
<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/SpringContextConfiguration.xml</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<listener>
		<listener-class>com.liferay.portal.kernel.servlet.HookContextListener</listener-class>
	</listener>
Even though all beans are initialized、I can't get in service class、it doesn't work on my case. 
The only way I can get beans is read the Spring Configration.xml in the service class.The n use Apple Apple Contront to get beans.Hard code.
private static ApplicationContext context = new ClassPathXmlApplicationContext("../SpringContextConfiguration.xml");
private IOrganizationStatusManager organizationStatusManager = context.getBean(
			"organizationStatusManager", IOrganizationStatusManager.class);
This is my solution to do that,if anyone has good solution,please let me know.Thanks in advance!
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Here is to show another way,a better way to this.I need to thanks my coworker Bin.He helped me figur it out.
The baic idea is to use a spring utill class、let me show you the code.
SpringUtil.java.The class is singleton.
public class SpringBeanUtil {
	
private static SpringBeanUtil instance = new SpringBeanUtil();
	
	private static IOrganizationStatusManager organizationStatusManager;
	
	private SpringBeanUtil () {}

	public static SpringBeanUtil getInstance() {
		return instance;
	}
	
	public void setInstance(SpringBeanUtil newInstance) {
		instance = newInstance;
	}

	public IOrganizationStatusManager getOrganizationStatusManager() {
		return organizationStatusManager;
	}
	
	public void setOrganizationStatusManager(IOrganizationStatusManager organizationStatusManager) {
		SpringBeanUtil.organizationStatusManager = organizationStatusManager;
	}
	
}
In our spring context.xml,we need to define the beans,it doesn't work by using annotation.We have to explicit wire the beans.
<bean id="springBeanUtil" class="org.myproject.organizationhook.util.SpringBeanUtil">
		<property name="organizationStatusManager" ref="organizationStatusManager"></property>
</bean>
Organization Storts Manager.java
@Service("organizationStatusManager")
@Transactional("organizationTransactionManager")
public class OrganizationStatusManager implements IOrganizationStatusManager {

	@Autowired
	@Qualifier("organizationStatusDao")
	private IOrganizationStatusDao organizationStatusDao;

	//isDeleted = 0 means the organization isn't deleted
	public int addOrganizationStatus(long organizationId) {		
		return null;
	}

	public String getSNByOrganizationId(long organizationId) {
		return null;
	}

	public long countOrgStatuses() {
		return 0L;
	}

	public void updateOrganizationStatus(long organizationId) {
	}

	public int addLastUpdateStatus() {	
		return 0;
	}

	public void deleteOrganizationStatus(long organizationId) {	
	}

}
The last thing we need to do is when we deploy the hook project,load the configration file.We add listener in web.xml
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/springcontext.xml</param-value>
</context-param>


<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
In web.xml,if we don't specify context-param to give a specific name for the file,the default name is appication Contront.xt.xml
Now,in our MyOrganization Local ServiceImpl.java,we use the IOrganization Manager class like this:
That's allThe tricky thing here is we can't add annotation on Spring BenUtil,even though we add that,in MyOrganization Locance ServiceImpl clast also get null.We have to explicit wire those bens.sprintingconml.
public class MyOrganizationLocalServiceImpl extends OrganizationLocalServiceWrapper {
	
private IOrganizationStatusManager organizationStatusManager = SpringBeanUtil.getInstance().getOrganizationStatusManager();

//...more
The second way is better than the first one.We don't take care of the spring beans maualy,tomcat tars care of that.
--------------------------------The Third Way--------------------------------------------------
I just learned a new way from my coworker Bin to get the bean.This would be the best way to that.Spring is so powerful to meet our requiremens.
This way is very easure,you just need to write another class and directlycal it.We need to get the help of BenFactory.
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component;

@Component("beanFactoryUtil")
public class BeanFactoryUtil implements BeanFactoryAware{
	
	private static BeanFactory beanFactory = null;

	public void setBeanFactory(BeanFactory beanFactory1) throws BeansException {
		beanFactory = beanFactory1;
	}
	
	public static BeanFactory getBeanFactory(){
		return beanFactory;
	}

}
This class is only used to get BenFactory、then we use it to get beans in our class:
private IOrganizationStatusManager organizationStatusManager = (IOrganizationStatusManager) BeanFactoryUtil.getBeanFactory().getBean("organizationStatusManager");
That's all.It's really easy right.
ノート:
If you're developing on Servlet,you don't need to write the BenFactoryUtil class,you can directly get beans like this:
BeanFactory bf = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
I tried to get Servlet Context in my wrapper class,but it throws Exception which I didn't find a good answer until now.
PortletBag portletBag = com.liferay.portal.kernel.portlet.PortletBagPool.get(serviceContext.getPortletId());
ServletContext servletContext = portletBag.getServletContext();
BeanFactory bf = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
Exceptionメッセージ:
21:00:14,035 ERROR [render_portlet_jsp:154] java.lang.IllegalStateException: Context attribute is not of type WebApplicationContext: Root WebApplicationContext: startup date [Fri Dec 21 20:25:57 GMT 2012]; root of context hierarchy
	at com.rujuan.organizationhook.custom.MyOrganizationLocalServiceImpl.updateOrganization(MyOrganizationLocalServiceImpl.java:63)
	at com.liferay.portal.kernel.bean.ClassLoaderBeanHandler.invoke(ClassLoaderBeanHandler.java:54)
	at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:112)
	at com.liferay.portal.spring.transaction.TransactionInterceptor.invoke(TransactionInterceptor.java:71)
	at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:108)
	at com.liferay.portal.spring.aop.ServiceBeanAopProxy.invoke(ServiceBeanAopProxy.java:211)
	at com.liferay.portal.service.impl.OrganizationServiceImpl.updateOrganization(OrganizationServiceImpl.java:587)
	at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:112)
	at com.liferay.portal.spring.transaction.TransactionInterceptor.invoke(TransactionInterceptor.java:71)
	at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:108)
	at com.liferay.portal.spring.aop.ServiceBeanAopProxy.invoke(ServiceBeanAopProxy.java:211)
	at com.liferay.portal.service.OrganizationServiceUtil.updateOrganization(OrganizationServiceUtil.java:427)
	at com.liferay.portlet.usersadmin.action.EditOrganizationAction.updateOrganization(EditOrganizationAction.java:239)
	at com.liferay.portlet.usersadmin.action.EditOrganizationAction.processAction(EditOrganizationAction.java:86)
	at com.liferay.portal.struts.PortletRequestProcessor.process(PortletRequestProcessor.java:175)
	at com.liferay.portlet.StrutsPortlet.processAction(StrutsPortlet.java:212)
	at com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:70)
	at com.liferay.portal.kernel.portlet.PortletFilterUtil.doFilter(PortletFilterUtil.java:48)
	at com.liferay.portlet.InvokerPortletImpl.invoke(InvokerPortletImpl.java:651)
	at com.liferay.portlet.InvokerPortletImpl.invokeAction(InvokerPortletImpl.java:686)
The reason is the root of ServletConteet I passed in is not WebAppliation Controtext rather than PortletApple Contect.