Springboot与各组件之间的整合(二)

@TOC

Springboot项目打包

SpringBoot项目可以是jar类型的maven项目,也可以是一个war类型的maven项目,取决于我们要不要整合jsp使用。但是不管是哪种项目类型,已经不是我们传统意义上的项目结构了
在本地使用SpringBoot的启动器即可访问我们开发的项目。如果我们将项目功能开发完成后,需要使用SpringBoot的打包功能来将项目进行打包。

SpringBoot项目打包在linux服务器中运行:
①jar类型项目会打成jar包:
jar类型项目使用SpringBoot打包插件打包时,会在打成的jar中内置一个tomcat的jar。所以我们可以使用jdk直接运行该jar项目可,jar项目中有一个功能,将功能代码放到其内置的tomcat中运行。我们直接使用浏览器访问即可。
②war类型项目会打成war包:
在打包时需要将内置的tomcat插件排除,配置servlet的依赖。将war正常的放到tomcat服务器中运行即可。

打包插件

 <build>
        <plugins>
           <plugin><!--  打包插件-->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                </configuration>
            </plugin>
        </plugins>
    </build>

在这里插入图片描述
在这里插入图片描述
项目打成jar包运行

.jar.original文件里的内容
在这里插入图片描述
打包好之后就可以直接在JDK环境中运行了;
在这里插入图片描述

其实在打包的时候可以指定打包的类型----jar/war
默认为jar,打包的jar可以直接运行,如果打包成war可以直接部署在服务器上;(打包时已经继承了tomcat)

在这里插入图片描述
项目导出war包运行;

打成war包由于是要将war包放在服务器上去运行,而服务器上是有自己的tomcat的,所以在打包war时要将spring boot自带的tomcat排除,(如果代码中需要req与resp,那么可以再次单独导入tomcat依赖,并将作用范围指定为编译时生效—provided);

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <!--    排除自带的tomcat-->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <!--打包的时候可以不用包进去,别的设施会提供。事实上该依赖理论上可以参与编译,测试,运行等周期。
                相当于compile,但是打包阶段做了exclude操作-->
            <scope>provided</scope>
        </dependency>

打包好的项目目录结构
在这里插入图片描述
war.original文件中的内容
在这里插入图片描述
接着将war包放到本地tomcat服务器webapp中

在这里插入图片描述
然后运行本地tomcat,启动之后会自动扫描war项目.并将该war解压;

在这里插入图片描述

这样可以访问我们的项目吗?----404找不到,什么原因?项目路径的问题,
在这里插入图片描述
我们来看tomcat解压后的项目上下文路径,
在这里插入图片描述
所以访问时的路径如下
在这里插入图片描述
打成war项目的上下文路径由实际路径决定(wa包名)而不是按照我们指定的上下文路径,同时如果我们在项目中指定端口,那么这时候也会失效,而是按照服务器的配置去运行;

如果我们使用的是tomcat7则需要将javax.el-api-3.0.0.jar包放到tomcat下 的lib目录中。

SpringBoot对异常的友好处理

我们在写代码时有时候会遇到一些异常,如果直接返回异常的代码,对用户来讲并不是很友好,这事后我们你可以在templates文件夹下建立一个专门用于存放反馈异常信息的页面

异常返回页面的命名规则—是404错误,就将该页面命名为404,则发生404错误时会跳到这个页面;同理500
目录结构---->>
在这里插入图片描述
这时候在controller中手动添加一个异常 int i=1/0;
在这里插入图片描述

在这里插入图片描述

但是又可能会遇到别的4或者5的错误,这样的话,我们可以将 页面命名为4xx,5xx,即可

还可以定义一个统一的页面—error.html

在这里插入图片描述

异常跳转的优先级---->>

当template/error文件夹下有相应的错误反馈页面时会优先走这里,如果没有则会走template下的error.html;

按照有异常就要处理的原则,我们可通过注解的方式来完成异常的处理;

 @ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
    public String errorHandler(){

        return "forward:/templates/error";
    }

这是局部异常处理,如果要做到全局异常处理

定义一个全局异常处理—>>
此处优先级低于局部异常处理器

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
    public String ExceptionHandler(){

        return "forward:/templates/error";
    }
}

自定义异常处理

import java.util.Properties;
/**
 * @author Gavin
 */
    @Configuration
public class GlobalExceptionHandler {
    @Bean
    public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){

        SimpleMappingExceptionResolver exceptionResolver= new SimpleMappingExceptionResolver();
        Properties properties= new Properties();
        properties.put("java.lang.NullPointException","../static/error.html");
        properties.put("java.lang.ArithmeticException","../static/error.html");
        exceptionResolver.setExceptionMappings(properties);
        return exceptionResolver;
    }
}

还有一种是通过配置xml了来实现,这里看链接吧;


/**
 * @author Gavin
 */
    @Configuration
public class GlobalExceptionHandler implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
       ModelAndView modelAndView= new ModelAndView();
       if(ex instanceof ArithmeticException ){
           modelAndView.setViewName("../static/error.html");
       }
       if(ex instanceof NullPointerException){
           modelAndView.setViewName("../static/error.html");
       }
        return modelAndView;
    }
}

还是springboot中自带的异常处理比较方便;

springboot中的测试单元

在这里插入图片描述
test单元的运行逻辑----->>当运行测试单元时会加载spring的运行环境;

package com.gavin.zzy;

import com.gavin.pojo.Goods;
import com.gavin.service.GoodsService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class ZzyApplicationTests {
@Autowired
    private GoodsService goodsService;
    @Test
    void contextLoads() {
        List<Goods> goods = goodsService.showGoods();
        goods.forEach(System.out::println);
    }

}

在这里插入图片描述
在测试的时候一般测试类的目录结构跟项目的目录结构保持一致;
若不这样可能由于版本的问题会出现一些错误;

  1. 测试类不能叫做Test,会和注解同名
  2. 测试方法必须是public
  3. 测试方法返回值必须是void
  4. 测试方法必须没有参数

Springboot对Bean的管理

Spring Boot 由于没有XML文件,所有的Bean管理都放入在一个配置类中实现。
配置类就是类上具有@Configuration的类。这个类就相当于之前的applicationContext.xml

1 新建一个配置类
com.codemar.config.MyConfig , 在springboot中最好是单独建一个配置类文件夹,方便维护(虽然可以直接放在resources文件夹下);
注意:配置类要有@Configuration,方法要有@Bean

@Configuration
public class MyConfig {
    //访问权限修饰符没有强制要求,一般是protected
    //返回值就是注入到Spring容器中实例类型。
    // 方法名没有强制要求,相当于<bean >中id属性。
    @Bean
    protected User getUser(){
        User user = new User();
        user.setId(1L);
        user.setName("张三");
        return user;
    }
    //自定义bean名称
    @Bean("user2")
    protected  User getUser2(){
        User user = new User();
        user.setId(2L);
        user.setName("李四");
        return user;
    }
}

如果Spring容器中存在同类型的Bean通过Bean的名称获取到Bean对象。或结合@Qualifier使用

 @SpringBootTest
public class TestGetBean {
    @Autowired
    @Qualifier("user2")
    private User user;
    @Test
    public void testGetUser(){
        System.out.println(user);
    }
}

在配置类的方法中通过方法参数让Spring容器把对象注入。
//自定义bean名称

@Bean("user1")
public  User getUser(){
    User user = new User();
    user.setId(2L);
    user.setName("李四");
    return user;
}
@Bean
//可以直接从方法参数中取到。
public People getPeople(User user1){
    People p = new People();
    p.setUser(user1);
    return p;
}

springboot拦截器

首先配置一个拦截器

package com.gavin.intercepter;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author Gavin
 */
@Component//bean注入
public class MyIntercepter implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器执行了");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

拦截器准备完毕后,拦截器不像其他的bean需要的时候注入即可,拦截器要的是全局,所以要配置一个配置类使得拦截器能够全局生效;

package com.gavin.intercepter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration//拦截器配置类
public class INTERCEPTERCONFIG implements WebMvcConfigurer {

@Autowired  //自动装配

 private MyIntercepter intercepter;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注入拦截器,添加拦截路径与放行路径
        InterceptorRegistration interceptorRegistration = registry.addInterceptor(intercepter).addPathPatterns("/**") .excludePathPatterns("/login");
    }
}

springboot中的注解

@SpringBootApplication
查看源码可以发现该注解其实是一个符合注解,该注解等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(“com.gavin”)

三个注解,
在这里插入图片描述
前面的文章已将对此做了解释,不在赘述了,只看结果;

在这里插入图片描述
在这里插入图片描述
@Configration

定义一个配置类,在配置类中注册一个bean
在这里插入图片描述

在启动的时候就会将user的信息加载到上下文的域中,这个时候我们可以从上下文中取出这些信息;

@SpringBootApplication
public class ZzyApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(ZzyApplication.class, args);
        User getUser = context.getBean("getUser", User.class);
        System.out.println(getUser);
    }

}

这个注解跟前面文章提到的import注解还不太一样,improt是通过无参构造来完成注入的;
比如说---->>

package com.gavin.config;

import com.gavin.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * @author Gavin
 */
@Configuration
@Import(value = User.class)
public class MyConfig {

    @Bean
    public User  getUser(){
        return new User("张三",23);
    }
}

package com.gavin;
import com.gavin.config.MyConfig;
import com.gavin.pojo.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

/**
 * @author Gavin
 */
@SpringBootApplication
public class ZzyApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(ZzyApplication.class, args);
        User getUser = context.getBean("getUser", User.class);
        System.out.println(getUser);
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        User getUser1 = annotationConfigApplicationContext.getBean("getUser", User.class);
        System.out.println(getUser1);
        String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
        for (String b :
                beanDefinitionNames) {
            System.out.println(b);
        }
    }

}

在这里插入图片描述

可以看到当我们注入bean时默认的注入bean的名为方法名------此时是按照类的type来装配的;

如果要按照id来装配,需要指定bean的id值;
在这里插入图片描述

在这里插入图片描述

初始化加载的类----->>org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory

代码分析---->>

   MyConfig bean = context.getBean(MyConfig.class);
        MyConfig bean2 = context.getBean(MyConfig.class);

//        spring中的单例设计   true
        System.out.println(bean==bean2);
        System.out.println("-----------------------");
        //从context中获取   true
        User user = bean.getUser();
        User user1 = bean.getUser();
        System.out.println(user==user1);
        System.out.println("-----------------------");
        // 自己new色结果为false,不做解释
            MyConfig M= new MyConfig();
        User user2 = M.getUser();
        User user3 = M.getUser();
System.out.println(user2==user3);

在@Configration注解中我们发现

package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";

    boolean proxyBeanMethods() default true;
}

boolean proxyBeanMethods() default true;

代理Bean方法默认为true,所以 我们在容器中获取Myconfig对象并非是一个真实的对象,而是一个代理对象,所以多次从容器中取出时会先判断有没有,如果有则返回该对象,否则就先建一个代理对象;

如果设置代理bean方法为false,其结果就会发生变化;
在这里插入图片描述
我们查看一下获得的对象真实名

   MyConfig bean = context.getBean(MyConfig.class);
        String simpleName = bean.getClass().getSimpleName();
System.out.println(simpleName);
MyConfig$$EnhancerBySpringCGLIB$$6c794284

代理模式—>>

当我们设置@Configuration(proxyBeanMethods = false)
返回结果
在这里插入图片描述

MyConfig配置类本身也是一个spring容器中的bean

  • proxyBeanMethods=true 属性,给MyConfig对象产生一个代理对象
  • 通过代理对象控制反复调用MyConfig里面的方法返回的是容器中的一个单实例
  • 如果proxyBeanMethods=false 那么我们拿到的MyConfig对象就不是一个代理对象, 那么这个时候反复调用MyConfig中的方法返回的就是多实例

proxyBeanMethods=false 称之为Lite模式 特点启动快

proxyBeanMethods=true 称之为Full模式 特点依赖spring容器控制bean单例

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeMartain

祝:生活蒸蒸日上!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值