欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识
原文出处: Fooisart

团结源码阐明 Spring 容器与 SpringMVC 容器之间的干系


问题

问题描写:项目中发明,自界说切面注解在 Controller 层正常事情,在 Service 层却无法正常事情。为了便于阐明,去掉代码中的业务逻辑,只留下场景。

自界说注解,打印时间

/**
 * Description: 自界说打印时间的注解
 * Created by jiangwang3 on 2018/5/9.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface PrintTime {
}

注解理会器

/**
 *Description:打印时间注解的理会器
 * @author jiangwang
 * @date 11:28 2018/5/14
 */
@Aspect
public class PrintTimeProcessor {
    private Logger LOGGER = LoggerFactory.getLogger(getClass());
    @Pointcut("@annotation(com.foo.service.annotation.PrintTime)")
    public void printTimePoint() {
    }
    @Around("printTimePoint()")
    public Object process(ProceedingJoinPoint jp) throws Throwable{
        System.out.println();
        LOGGER.error("开始运行措施。。。Start==>");
        Object proceed = jp.proceed();
        LOGGER.error("竣事啦,运行竣事==>");
        System.out.println();
        return proceed;
    }
}

Controller层

/**
 * @author jiangwang
 * @date  2018/5/14
 */
@RestController
@RequestMapping(value = "/user")
public class UserController {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Resource
    private UserService userService;
    @RequestMapping(value = "/serviceAspect", method={RequestMethod.GET})
    public  String serviceAspect(){
        return userService.serviceAspect();
    }
    @RequestMapping(value = "/controllerAspect", method={RequestMethod.GET})
    @PrintTime
    public  String name(){
        logger.info("Controller层----测试切面");
        return "controllerAspect";
    }
}

Service层

/**
 * @author jiangwang
 * @date 11:34 2018/5/14
 */
@Service
public class UserService {
    private Logger logger = LoggerFactory.getLogger(getClass())
    @PrintTime
    public String serviceAspect(){
        logger.info("Service层---测试切面");
        return "serviceAspect";
    }
}

spring.xml 设置文件,主要部门

<context:annotation-config />
<!-- 动态署理开启 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<context:component-scan base-package="com.foo" >
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 民众设置引入 -->
<import resource="classpath:spring/spring-config-dao.xml" />

springmvc.xml 设置文件,主要部门

<mvc:annotation-driven />
<mvc:default-servlet-handler />
<!-- 动态署理开启 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<!-- mvc controller -->
<context:component-scan base-package="com.foo.web.controller" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
<bean class="com.foo.service.processor.PrintTimeProcessor"/>

以上为主要代码。项目运行之后,发此刻 Service 层的注解切面未生效,而在 Controller 层正常。而当我将 springmvc.xml 中的

<bean class="com.foo.service.processor.PrintTimeProcessor"/>

迁移至 spring.xml 中,发明 Service 层与 Controller 层的注解切面均可正常运行。WHY???


从源码的角度探究该问题

由于源码中的要领较长,所以只贴出重点且与主题相关的代码。发起团结当地源码一起看。

为了说清楚这个问题,咱们先看一下Spring容器是如何实现 Bean 自动注入(简化版)

Web 项目标进口是 web.xml,所以咱们从它开始。

web.xml 设置文件,主要部门

<!-- Spring Config -->
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:spring/spring-config.xml</param-value>
</context-param>

<!-- SpringMvc Config -->
<servlet>
  <servlet-name>springMvc</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/spring-mvc.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>springMvc</servlet-name>
  <url-pattern>/*</url-pattern>
</servlet-mapping>

Spring 容器 Bean 加载流程