Topic: [求助][急]如何将活动的servlet 注入 bean里

  Print this page

1.[求助][急]如何将活动的servlet 注入 bean里 Copy to clipboard
Posted by: cliff
Posted on: 2006-10-27 15:53

在web.xml定义的servlet,如何在该servlet装入服务器后注入由spring管理的bean?

例如
在web.xml中定义了

  <servlet>
<servlet-name>some</servlet-name>
<servlet-class>SomeServlet</servlet-class>
</servlet>


在 applicationContext.xml中定义了

<beans>
...
<bean id="servlet" class="SomeServlet"/>


   <bean id="someBean" class="SomeBean">
<property name="servlet">
<ref bean="servlet"/>
</property>
</bean>

...
</beans>

上面这样的话,注入的servlet并不是装入服务器的那个servlet, 怎样才能将装入服务器的那个servlet注入 SomeBean?

2.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: cliff] Copy to clipboard
Posted by: floater
Posted on: 2006-10-27 21:34

sounds like a wrong way to go.

3.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: floater] Copy to clipboard
Posted by: cliff
Posted on: 2006-10-27 23:21

floater wrote:
sounds like a wrong way to go.



so what's your suggestion? please indicate a right way!
sometimes you need to get env variables to handle some logic such as session checking, how could you do that without them?


I have to emphasize that I don't want to involve Spring MVC.

THe general question about this issue is that we have some env object created by the server, and we want to get that to handle something. Since the objects are created by the server, we don't know how to get them outside the server env. If we use servlet or Struts or any other framework, we know that all the env objects are injected by the server, we can get them as the methed's parameter or server objects' properties. So we don't want to care about them, anytime we want to use them, we can get them.

4.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: cliff] Copy to clipboard
Posted by: floater
Posted on: 2006-10-28 02:05

good comment, so I now know your intention.

I think this *is* a valid usage, if I understand you correct, basically you are trying to get some settings somewhere else on the network.

Here is my experience/suggestions. If this somewhere is local, Spring has various ways to do that. If this is on the network(in your case, a http servlet container?),
it would be better to write a seperate class to extract the properties, then inject this seperate class in your beans. Furthermore, it should be possible to do it in such a way that you can isolate the particular way to extract. This is particular helpful during testing.

The reason I sense that injecting a servlet in a bean is that you at least implicitly/explicitly has the dependency on servlets, which is running on a server. That's a little bit overkill. If indeed there is a need, maybe the other way around is better, do it in the servlet context, i.e., either in the servlet or in the interceptor.

Another note is that since we are on the network, this usage has a sweetspot that Spring doesn't address, i.e., refresh the application context, i.e., revalidate your settings. If you have this requirement, you are stuck, like I do. I asked Rod Johnson once, but he kind of avoided the question, just vaguely saying that they are going to address that in spring 2.1.

my 2 cents.

5.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: cliff] Copy to clipboard
Posted by: cliff
Posted on: 2006-10-28 12:07

"If indeed there is a need, maybe the other way around is better, do it in the servlet context, i.e., either in the servlet or in the interceptor."
about this sentence, I am confused! I know what you mean, you mean handle the action in the servlet if you want to use the servlet, as you don't need to care about where the servlet is , it's just there.

Let's consider a scenario:
With struts, you have more then 10 action classes(inheriting DispatchAction), in each action you have more than 5 action methods. You define a common class which have all the common methods, and you have to apply all these methods of this class in each method of every action class. But you have to set the ActionServlet as the property of this common class, since you have to get the session attribute in this common methods. One way to inject ActionServlet to this common class is to pass the servlet property of Action(we know action has a property named servlet which represents the ActionServlet instance) to it in each method of each action. It's ugly to do so, everytime you add a new method in the action class, you have to copy the code of injecting servlet and call the common methods of the common class.

Another approach is to use interceptor, just as you say. You can implement MethodBeforeAdvice to setup the interceptor and do the logic in the before() method.


public class SomeInterceptor implements MethodBeforeAdvice {

public void before(Method method, Object[] objects, Object o)
throws Throwable {

ActionMapping mapping=(ActionMapping)objects[0];
ActionForm form=(ActionForm)objects[1];
HttpServletRequest request=(HttpServletRequest)objects[2];
HttpServletResponse response=(HttpServletResponse)objects[3];

DispatchAction action=(DispatchAction)o;
ActionServlet servlet=(ActionServlet)action.getServlet();
...

}
}




public class SomeAction extends DispatchAction {

...

public ActionForward somefunction(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
...
}

...
}



we set this SomeInterceptor into every action method like somefunction()

checking these 2 snippets, you should notice several things:
1. the return type of the before() method is void.
2. the return type of somefunction() mnthod is ActionForward.
3. to get the ActionServlet context in the Interceptor, spring has inject them in the parameters of the before method, so you can hardcode to get them, ok, this is fine, but not stable, we can not make sure each time the parameters are just like these ones in every type of server(tomcat, weblogic, websphere ...).
4. in before() meothd , after checking some logic with these parameters, if some conditions are satisfied, we don't want to continue the process of somefunction() method, we just want to end up the somefunction() and return ActionForward. In before() method, how can we indicate somefunction() method to end up and return the ActionForward. With Spring AOP, how can we do that?

Please give more advices, thank you.


6.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: cliff] Copy to clipboard
Posted by: floater
Posted on: 2006-10-28 23:06

1, 2, and 4 are all related to aop, since the explanation is fairly long, you may pick up a few references/books/google "spring aop" instead. The short version is to use around advise to branch out based on your conditions. You can choose to proceed or otherwise.

You may formulate your problem downward to try it out, e.g., just create a simple bean with one method that returns an int(you can hardcode the returning int, say 5), then try to intercept it in spring aop. This is a much smaller problem than the original big one.

For #3, if we stay in the j2ee spec, you should be able to get a stable base, after all you are dealing with servlets, etc. If not, then you need to abstract them out in a certain way, e.g., build an interface with concrete classes for different types of servers, and use the interface in your interceptor.

In your first approach, you may build an intermediate class between DispatchAction and your actions to handle the common class functionalities. This is a general STRUTS standard practice anyway. That should work too, I've done that twice before. But I like aop approach more since it's a more natural way.

7.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: cliff] Copy to clipboard
Posted by: cliff
Posted on: 2006-10-29 01:14

For the aop approach, I have tested, it really works, thank you very much.

However, for the "general STRUTS standard practice", I really don't understand how to do it, "build an intermediate class between DispatchAction and your actions "", how can the intermediate class communicate with the DispatchAction and actions without hardcode in each action method? Please give me a simple example to show your way, thank you again.

8.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: cliff] Copy to clipboard
Posted by: floater
Posted on: 2006-10-29 23:32

Basically, you inherit from DispatchAction, say class A, and put all common logic in A, then all the actual action classes are inherited from A and thus have access to the common part. If you have a fixed logic in the action thread, you could even use a template too, but there are quite a few variants so I leave them out.

Basically, you do whatever you need to do, then refactor them out to a proper dependency level.

9.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: cliff] Copy to clipboard
Posted by: cliff
Posted on: 2006-10-30 14:33

About autoproxing BeanNameAutoProxyCreator, I have a related question:

As you know, in order to take the second approach, I need to apply more than one interceptor to different targets(action methods).
Let me explain it with a example:

There are two interceptors, InterceptorA and InterceptorB and two targets, TargetA and targetB, I want to use autoproxing BeanNameAutoProxyCreator to apply InterceptorA to TargetA and InterceptorB to TargetB, in applicationContext.xml, if I do it this way:


<bean name="targetA" class="TargetA"/>
<bean name="targetB" class="TargetB"/>

<bean name="interceptorA" class="InterceptorA"/>
<bean name="interceptorB" class="InterceptorB"/>


<bean name="autoProxyA"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">

<property name="beanNames">
  <list>
    <value>targetA</value>
  </list>
</property>
<property name="interceptorNames">
<list>
<value>interceptorA</value>
</list>
</property>
</bean>


<bean name="autoProxyB"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">

<property name="beanNames">
  <list>
    <value>targetB</value>
  </list>
</property>
<property name="interceptorNames">
<list>
<value>interceptorB</value>
</list>
</property>
</bean>


when I try to run it, the exception org.springframework.beans.factory.BeanNotOfRequiredTypeException would be threw out,

I find that it's because I define BeanNameAutoProxyCreator twice , and I use different bean name(autoProxyA,autoProxyB).
Even if I add the attribute "singleton="false"", it still doesn't work.

But if I define BeanNameAutoProxyCreator only once, I don't konw how to make sure InterceptorA only be applied to TargetA,
and InterceptorB only be applied to TargetB.

So what do you think about this problem:

how do we use "BeanNameAutoProxyCreator" to apply different interceptors to different targets?

10.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: cliff] Copy to clipboard
Posted by: floater
Posted on: 2006-10-30 22:25

try give them different ids

<bean id="autoProxyB" ...

11.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: floater] Copy to clipboard
Posted by: cliff
Posted on: 2006-10-31 10:00

floater wrote:
try give them different ids

<bean id="autoProxyB" ...


It doesn't work either.

12.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: cliff] Copy to clipboard
Posted by: floater
Posted on: 2006-10-31 22:58

try setting the proxyTargetClass property to true for the BeanNameAutoProxyCreator definition or google for this, I've never seen this before.

13.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: cliff] Copy to clipboard
Posted by: floater
Posted on: 2006-10-31 23:07

one thing I notice you always use bean name attribute, did you replace these with id attribute everywhere?

name is just an alias, not the identifier. we should use id always at least.

14.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: floater] Copy to clipboard
Posted by: cliff
Posted on: 2006-11-01 10:09

floater wrote:
try setting the proxyTargetClass property to true for the BeanNameAutoProxyCreator definition or google for this, I've never seen this before.


Thank you for your solution, it works now after I set the property "proxyTargetClass" to be true in the class BeanNameAutoProxyCreator.


Dynamic Proxy in java is the best way for AOP, but only suitable for interface not class.
If you want to use class, Spring AOP will use CGLib to genearte the subclass of the target class to implement AOP.
In this way, we should set the propery "proxyTargetClass" to be true in the Proxy class.


15.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: floater] Copy to clipboard
Posted by: cliff
Posted on: 2006-11-01 10:17

floater wrote:
one thing I notice you always use bean name attribute, did you replace these with id attribute everywhere?

name is just an alias, not the identifier. we should use id always at least.


ID will cause error when the content has some special character, such as "/", in this case, name is the only choice

16.Re:[求助][急]如何将活动的servlet 注入 bean里 [Re: cliff] Copy to clipboard
Posted by: floater
Posted on: 2006-11-01 22:15

oh, forgot you are using that for urls.


   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923