- 配置velocity自定标签。
- 调试时发现自定义标签类由spring依赖注入的实例service方法为null。
- 断点跟踪自定义标签继承类Directive的init方法。发现@Resource、@Autowired注入无效的原因是用户自定义标签类的实例由反射生成,不由spring容器创建。
org.apache.velocity.runtime.directive.Directive.init()
->
org.apache.velocity.runtime.RuntimeInstance.init()
->
org.apache.velocity.runtime.RuntimeInstance.initializeDirectives()
->
loadDirective() 【自定义标签实例创建方法】 - 查看Directive.init(),断点入参RuntimeServices类,发现该类中有引用servlet容器的上下文,并可以用getApplicationAttribute()取出。
重写自定义标签类中的init的方法,使用RuntimeServices类获取上下文容器。
servletContent转换为->WebApplicationContex->并使用WebApplicationContext.get获取service实例方法并直接设置。 - 页面正常断点执行velocity自定义标签类的render方法时可以看到spring管理的实例时已注入。
可在自定义标签类中重写init方法通过RunTimeServices获取spirng上下文获取service业务实例。 - 代码:
import org.apache.velocity.context.InternalContextAdapter; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; import org.apache.velocity.exception.TemplateInitException; import org.apache.velocity.runtime.RuntimeServices; import org.apache.velocity.runtime.directive.Directive; import org.apache.velocity.runtime.parser.node.Node; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import javax.servlet.ServletContext; import java.io.IOException; import java.io.Writer; public class OrderSourceSelectDirective extends Directive { private RuleFacadeService ruleFacadeService;//业务service @Override public void init(RuntimeServices rs, InternalContextAdapter context, Node node) throws TemplateInitException { super.init(rs, context, node); ServletContext sc = (ServletContext) rs.getApplicationAttribute("javax.servlet.ServletContext"); //获取servlet上下文容器 WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(sc);//获取spring上下文容器 this.ruleFacadeService = webApplicationContext.getBean(RuleFacadeService.class); //从spring容器中取出service层实例,设值此反射创建的自定义标签类实例中 } /** * 标签名 */ @Override public String getName() { return "orderSourceSelect"; } /** * 标签类型 * LINE: 不要#end结束符, * BLOCK:需要#end结束符 */ @Override public int getType() { return LINE; } /** * 标签输出内容 */ @Override public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException, ResourceNotFoundException, ParseErrorException, MethodInvocationException { System.out.println(ruleFacadeService); //业务service return true; } }