框架原理

一次springMVC项目改造为springBoot项目的经历

2019-04-16  本文已影响55人  java_飞

情景:事情发生在即将离职前二周,接到任务,因为其余项目都已经改造为boot项目,然后目前只剩一个比较大的MVC项目,还没改造完,为了使以后docker部署更加便捷,所以接下去需要把这个MVC项目改造为boot项目;

开工:创建一个新的boot项目用来替代原来的MVC项目,接下去的重点就是MVC的一些相关配置,根据其他项目配置好相关的bean,例如rabbit,redis等,然后再将MVC项目中的dubbo-consumer.xml文件用properties文件进行配置,这里我boot集成dubbo用的jar包是

<dependency>
    <groupId>io.dubbo.springboot</groupId>
    <artifactId>spring-boot-starter-dubbo</artifactId>
    <version>1.0.0</version>
</dependency>

具体如何集成可以参考之前的文章;

这里遇到的第一个问题:启动以后老是报错,报错内容为找不到提供者,这个没问题,因为我提供者是没有启动,但是我MVC项目也是这样启动,但是没有报错;

寻找问题,发现MVC的xml文件配置里有一句

 <dubbo:consumer filter="HystrixFilter,MDCFilter,DubboExceptionFilter,-exception" timeout="10000"
                    check="false"/>

这句的作用是配置了自定义的拦截器,还有超时时间,最后一个是重点,意思是启动的时候不检查提供者是否已经启动(虽然很绕,但是意思就是这个意思);

那么boot里面是如何配置的呢?

看过之前写的文章可以知道,boot集成dubbo的时候,相关配置我是在applicaiton.properties文件里面编写的,如下:

spring.dubbo.scan=**.**.**.**//扫描的dubbo包路径
spring.dubbo.module.default=false
spring.dubbo.consumer.filter=MDCFilter,DubboExceptionFilter,-exception

那么关于消费者的检查如何关闭呢,我刚开始也不知道怎么关闭,那么很简单查看源码,前车之鉴,上面filter可以这样配置,我就点进去查看源码里面有没有check这个字段,答案是有的,如下:

public abstract class AbstractReferenceConfig extends AbstractInterfaceConfig {
    private static final long serialVersionUID = -2786526984373031126L;
    protected Boolean check;//这个应该就是那个是否关闭检查的属性,filter属性的话可以在进入AbstractInterfaceConfig 查看
    protected Boolean init;
    protected String generic;
    protected Boolean injvm;
    protected Boolean lazy;
    protected String reconnect;
    protected Boolean sticky;
    protected Boolean stubevent;
    protected String version;
    protected String group;

    public AbstractReferenceConfig() {
    }
}

找到解决方法就简单了,然后在配置文件中在加一句

spring.dubbo.consumer.check=false

启动项目后发现正常启动;关于dubbo相关的配置问题就到这里结束了;

然后就是配置MVC相关的东西了;
这里主要涉及到一个接口WebMvcConfigurer.class,自定义一个类然后实现该接口,代码如下:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Resource
    private AuthInterceptor authInterceptor;

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {

    }

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

    }

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {

    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

    }

    @Override
    public void addFormatters(FormatterRegistry registry) {


    }

//这个方法是添加自定义的拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor).addPathPatterns("/**");
   
    }

//这个方法是对一些静态资源的配置
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**/*.html").addResourceLocations("/**/");

    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {

    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {

    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {

    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new CurrentUserMethodArgumentResolver());
    }

    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {

    }

//这个方法是添加消息的转化器,例如空值转化,json序列化字段等功能
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
       
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {

    }

    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {

    }

    @Override
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {

    }

    @Override
    public Validator getValidator() {
        return null;
    }

    @Override
    public MessageCodesResolver getMessageCodesResolver() {
        return null;
    }
}

这里用到的不多,具体就那么几个东西,需要注意的地方是添加自定义拦截器的时候,加入你的拦截器里面需要注入spring对象,记得必须要加拦截器交给spring管理,有二种方法,第一种就是我上面所写的;第二种伪代码如下:

@bean
public MyInterceptor myInterceptor(){
return new MyInterceptor();
} 

@Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor()).addPathPatterns("/**");

    }

关于filter的配置如下:

 @Bean
    public FilterRegistrationBean ***FilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean(new ***Filter());
        registration.addUrlPatterns("/*"); //
        registration.setName("***Filter");
        registration.setOrder(1);
        return registration;
    }
    @Bean
    public FilterRegistrationBean sssFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean(new sssFilter());
        registration.addUrlPatterns("/*"); //
        registration.setName("sssFilter");
        registration.setOrder(2);
        return registration;
    }

注意这个bean必须配置在启动类里面,否则可能不生效;(我也没试过在别的地方配置,所以也不确定,嘿嘿😄);

一般情况下集成到这里差不多就已经结束了,一切都可以正常使用了;

接下来的问题一般人不太会遇到,可能我比较特殊吧,谁让我遇到了呢;

这个问题就是关于aop的,在MVC项目中一切都是正常的,但是在boot项目中,我启动后请求,发现能够正常进入aop切面,但是运行其中的代码后,我发现无法获取到该方法上面的注解,同事也获取不到该方法的参数名称,那么问题来了,这个到底是什么原因呢?

接下来开始百度,(不要问我为什么不google,我试过google,查出来的结果跟百度相差不大,而且比较穷,没钱翻墙)看看博客,大概看了一上午的博客吧,基本对我的情况都是没什么用的,突然看到一篇文章,出处忘记了,这个作者也是蛮有趣,因为这个问题思考了一晚上没能安心睡,他说到了aop的jdk代理和cglib代理,灵光一闪,我也很可能是这个问题,然后我启动项目测试,发现MVC项目中代理的目标类是该接口的实现类,而boot项目中代理的目标类确是个接口,原因找到了,就在这个地方,那么继续百度boot项目aop代理方式或者boot如何强制使用cglib代理,一找一大堆,并了解到,spring-boot2.0版本一下默认走的是jdk动态代理,而2.0版本以上默认走的是cglib代理(这里我是有疑问的,虽然我用的版本是1.5.4.RELEASE,走的是jdk,但是我同学用的是1.5.9.RELEASE,他跑起来却是正常的),如何强制走cglib呢,在配置文件中添加:

spring.aop.proxy-target-class=true

然后启动项目,一切正常,项目改造到此结束,如果改造过程中还遇到什么问题的话,希望大家一起分享,看过觉得有用的可以点个喜欢收藏一下(QQ:1107156537)

上一篇 下一篇

猜你喜欢

热点阅读