文章目录
- 一、spring总结
- 二、springboot总结
- 1、什么是Spring Boot,为什么要用?有哪些优点?
- 2、Spring Boot常用注解有那些?
- 3、运行Spring Boot有哪几种方式
- 4、如何理解Spring Boot中的Starters?
- 5、如何在Spring Boot启动的时候运行一些特定的代码?
- 6、Spring Boot需要独立的容器运行吗?
- 7、Spring Boot中的监视器是什么?
- 8、使用Spring Boot实现异常处理?
- 9、SpringBoot 实现热部署有哪几种方式
- 11、Spring Boot的核心配置文件优先级?
- 12、什么是JavaConfig?
- 13、如何重新加载Spring Boot上的更改, 而无需重新启动服务器?
- 14、Spring Boot 中定义Tomcat参数
- 23、如何实现Spring Boot应用程序的安全性?
一、spring总结
1、Spring三级缓存解决什么问题?
Map<String, Object> singletonObjects: 一级缓存,也就是我们平常理解的单例池,存放已经完整经历了完整生命周期的bean对象。
Map<String, Object> earlySingletonObjects: 二级缓存,存储早期暴露出来的bean对象,bean的生命周期未结束。(属性还未填充完)
Map<String,ObjectFactory<?> > singletonFactories: 三级缓存,存储生成bean的工厂
二级缓存可以解决没有aop的循环依赖。核心思路是
使用二级缓存来提前曝光创建过程中的对象
。使用二级缓存来解决aop循环依赖的问题是:bean对象属性填充的应该是代理对象
,而不是源对象。三级缓存解决aop循环依赖核心思路:
打破bean的生命周期,属性赋值时aop提前创建代理对象
。
2、Spring支持的几种bean的作用域?
singleton: bean在每个Springioc容器中只有一个实例。
prototype:一个bean的定义可以有多个实例。
request:每次http请求都会创建一个bean,该作用域仅在基于web的SpringApplicationContext情形下有效。
session:在一个HTTPSession中,一个bean定义对应一个实例。该作用域仅在基于web的SpringApplicationContext情形下有效。
global-session:在一个全局的HTTPSession中,一个bean定义对应一个实例。该作用域仅在基于web的SpringApplicationContext情形下有效。
缺省的Springbean的作用域是Singleton.
3、pring bean是否是线程安全?
Spring框架中默认是单例bean,是无状态的,不是线程安全的
*线程安全部分处理:
RequestContextHolder:用户上下文
SynchronizationManager:事务同步器实现
LocaleContextHolder:上下文
//spring通过ThreadLocal包裹对象保证多线程安全
private static final ThreadLocal localeContextHolder = new NamedThreadLocal<>(“LocaleContext”);
4、Spring框架中bean的生命周期?
bean实例化 ->属性填充->bean初始化->bean使用->bean销毁
Spring容器从XML文件中读取bean的定义,并实例化bean。
Spring根据bean的定义填充所有的属性。
如果bean实现了BeanNameAware接口,Spring传递bean的ID到setBeanName方法。
如果Bean实现了BeanFactoryAware接口,Spring传递beanfactory给setBeanFactory方法。
如果有任何与bean相关联的BeanPostProcessors,Spring会在postProcesserBeforeInitialization()方法内调用它们。
如果bean实现IntializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用此初始化方法。
如果有BeanPostProcessors和bean关联,这些bean的postProcessAfterInitialization()方法将被调用。
如果bean实现了DisposableBean,它将调用destroy()方法。
5、哪些是重要的bean生命周期方法?你能重载它们吗?
有两个重要的bean生命周期方法,第一个是setup,它是在容器加载bean的时候被调用。第二个方法是teardown它是在容器卸载类的时候被调用。
bean标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct和@PreDestroy)。
6、什么是bean装配?
装配,或bean装配是指在Spring容器中把bean组装到一起,前提是容器需要知道bean的依赖关系,如何通过依赖注入来把它们装配到一起。
自动装配: Spring容器能够自动装配相互合作的bean,这意味着容器不需要和配置,能通过Bean工厂自动处理bean之间的协作。
7、解释不同方式的自动装配?
有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入。
no:默认的方式是不进行自动装配,通过显式设置ref属性来进行装配。
byName:通过参数名自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
byType:通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。
constructor:这个方式类似于****byType,但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。
自动装配有哪些局限性:
重写:你仍需用和配置来定义依赖,意味着总要重写自动装配。
基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。
模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。
8、Spring如何实现AOP的?
spring aop基于 AspectJ动态代理 实现切面编程,实现下面5类通知方法
before:前置通知,在一个方法执行前被调用。
after: 在方法执行之后调用的通知,无论方法执行是否成功。
after-returning: 仅当方法成功完成后执行的通知。
after-throwing: 在方法抛出异常退出时执行的通知。
around: 在方法执行之前和之后调用的通知。
java动态代理技术有:AspectJ、JDK_Proxy、CGLIB_Proxy
AspectJ: spring默认基于AspectJ实现,AspectJ动态代理也是最好用的
JDK_Proxy、CGLIB_Proxy: 没有AspectJ好用
9、Spring事务传播级别?
事务代码隔离 & 事务传播级别 &事务本质
事务代码隔离:
spring默认是基于单例bean,线程不安全,其实现事务隔离SynchronizationManager接口及实现都基于Threadlocal修饰,提供线程安全隔离能力。
事务传播级别:
1、PROPAGATION_REQUIRED ,默认的spring事务传播级别,使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行。所以这个级别通常能满足处理大多数的业务场景。
2、PROPAGATION_SUPPORTS ,从字面意思就知道,supports,支持,该传播级别的特点是,如果上下文存在事务,则支持事务加入事务,如果没有事务,则使用非事务的方式执行。所以说,并非所有的包在transactionTemplate.execute中的代码都会有事务支持。这个通常是用来处理那些并非原子性的非核心业务逻辑操作。应用场景较少。
3、PROPAGATION_MANDATORY , 该级别的事务要求上下文中必须要存在事务,否则就会抛出异常!配置该方式的传播级别是有效的控制上下文调用代码遗漏添加事务控制的保证手段。比如一段代码不能单独被调用执行,但是一旦被调用,就必须有事务包含的情况,就可以使用这个传播级别。
4、PROPAGATION_REQUIRES_NEW ,从字面即可知道,new,每次都要一个新事务,该传播级别的特点是,每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。
5、PROPAGATION_NOT_SUPPORTED ,这个也可以从字面得知,not supported ,不支持,当前级别的特点就是上下文中存在事务,则挂起事务,执行当前逻辑,结束后恢复上下文的事务。
6、PROPAGATION_NEVER ,该事务更严格,上面一个事务传播级别只是不支持而已,有事务就挂起,而PROPAGATION_NEVER传播级别要求上下文中不能存在事务,一旦有事务,就抛出runtime异常,强制停止执行!这个级别上辈子跟事务有仇。
7、PROPAGATION_NESTED ,字面也可知道,nested,嵌套级别事务。该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务
10、spring 8种事务失效场景?
1、数据库引擎不支持事务
从 MySQL 5.5.5 开始的默认存储引擎是:InnoDB,之前默认的都是:MyISAM,所以这点要值得注意,底层引擎不支持事务再怎么搞都是白搭。2、没有被 Spring 管理
@Service public class OrderServiceImpl implements OrderService { @Transactional public void updateOrder(Order order) { // update order }}
如果此时把 @Service 注解注释掉,这个类就不会被加载成一个 Bean,那这个类就不会被 Spring 管理了,事务自然就失效了
3、方法不是 public 的
@Transactional 只能用于 public 的方法上,否则事务会失效,如果要用在非 public 方法上,可以开启 AspectJ 代理模式。4、自身调用问题
@Service public class OrderServiceImpl implements OrderService { public void update(Order order) { updateOrder(order); } @Transactional public void updateOrder(Order order) { // update order }}
update方法上面没有加 @Transactional 注解,调用有 @Transactional 注解的 updateOrder 方法,updateOrder 方法上的事务管用吗? 答案:管用先调updateOrder,在调update,事务会加入。反之就不管用。
再来看下面这个例子:
@Service public class OrderServiceImpl implements OrderService { @Transactional public void update(Order order) { updateOrder(order); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void updateOrder(Order order) { // update order }}
这次在 update 方法上加了 @Transactional,updateOrder 加了 REQUIRES_NEW 新开启一个事务,那么新开的事务管用么? 答案:不管用
5、数据源没有配置事务管理器
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
如上面所示,当前数据源若没有配置事务管理器,那也是白搭!
6、不支持事务
@Service public class OrderServiceImpl implements OrderService { @Transactional public void update(Order order) { updateOrder(order); } @Transactional(propagation = Propagation.NOT_SUPPORTED) public void updateOrder(Order order) { // update order }}
Propagation.NOT_SUPPORTED: 表示不以事务运行,当前若存在事务则挂起,详细的可以参考《事务隔离级别和传播机制》这篇文章。
都主动不支持以事务方式运行了,那事务生效也是白搭!
7、异常被吃了
// @Service public class OrderServiceImpl implements OrderService { @Transactional public void updateOrder(Order order) { try { // update order } catch { } }}
8、异常类型错误
// @Service
public class OrderServiceImpl implements OrderService {
@Transactional
public void updateOrder(Order order) {
try {
// update order
} catch {
throw new Exception(“更新错误”);
}
}}
这样事务也是不生效的,因为默认回滚的是:RuntimeException,如果你想触发其他异常的回滚,需要在注解上配置一下,如:
@Transactional(rollbackFor = Exception.class)
这个配置仅限于 Throwable 异常类及其子类。
1、spring的事务注解@Transactional只能放在public修饰的方法上才起作用,如果放在其他非public(private,protected)方法上,虽然不报错,但是事务不起作用
2、如果采用spring+spring mvc,则context:component-scan重复扫描问题可能会引起事务失败。
如果spring和mvc的配置文件中都扫描了service层,那么事务就会失效。
原因:因为按照spring配置文件的加载顺序来讲,先加载springmvc配置文件,再加载spring配置文件,我们的事物一般都在srping配置文件中进行配置,如果此时在加载srpingMVC配置文件的时候,把servlce也给注册了,但是此时事物还没加载,也就导致后面的事物无法成功注入到service中。所以把对service的扫描放在spring配置文件中或是其他配置文件中。3、如使用mysql且引擎是MyISAM,则事务会不起作用,原因是MyISAM不支持事务,可以改成InnoDB引擎
4、 @Transactional 注解开启配置,必须放到listener里加载,如果放到DispatcherServlet的配置里,事务也是不起作用的。
如果spring和mvc的配置文件中都扫描了service层,那么事务就会失效。
原因:因为按照spring配置文件的加载顺序来讲,先加载springmvc配置文件,再加载spring配置文件,我们的事物一般都在srping配置文件中进行配置,如果此时在加载srpingMVC配置文件的时候,把servlce也给注册了,但是此时事物还没加载,也就导致后面的事物无法成功注入到service中。所以把对service的扫描放在spring配置文件中或是其他配置文件中。5、Spring团队建议在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。在接口上使用 @Transactional 注解,只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。
6、在业务代码中如果抛出RuntimeException异常,事务回滚;但是抛出Exception,事务不回滚;
7、如果在加有事务的方法内,使用了try…catch…语句块对异常进行了捕获,而catch语句块没有throw new RuntimeExecption异常,事务也不会回滚。
8、在类A里面有方法a 和方法b, 然后方法b上面用 @Transactional加了方法级别的事务,在方法a里面 调用了方法b, 方法b里面的事务不会生效。原因是在同一个类之中,方法互相调用,切面无效 ,而不仅仅是事务。这里事务之所以无效,是因为spring的事务是通过aop实现的。
11、BeanFactory和FactoryBean与ApplicationContext的区别?
Spring提供了两种不同的IOC容器,一个是BeanFactory,另一个是ApplicationContext,他们都是Java Interface,ApplicationContext继承于BeanFactory(ApplicationContext继承ListableBeanFactory,而ListableBeanFactory继承BeanFactory)。
1、相同点
①他们都可以用来配置XML属性,也支持属性的自动注入。②BeanFactory和ApplicationContext都提供一种方式:使用getBean(“bean name”)获取容器中的Bean。
2、不同点
①当调用getBean()方法时,BeanFactory实例化bean,而ApplicationContext在容器启动的时候就已经实例化单例的bean了,不会在调用getBean()方法时再实例化。
②BeanFactory不支持国际化,即i18n,但ApplicationContext提供了对它的支持。
③BeanFactory与ApplicationContext的另一个区别是能够将事件发布到注册为监听器的bean。
④BeanFactory的一个核心实现是XMLBeanFactory,而ApplicationContext的一个核心实现是ClassPathXmlApplicationContext,Web容器的环境我们使用WebApplicationContext并且增加了getServeltContext方法。
⑤如果使用自动注入并使用BeanFactory,则需要API注册AutoWiredBeanPostProcessor,如果使用ApplicationContext,则可以使用XML进行配置。
2、FactoryBean使用规则
FactoryBean 用来生成某一个类型Bean实例,它最大的一个作用是:可以让我们自定义Bean的创建过程。比如说你有一些同属于某一类型的Bean对象需要被创建,但是它们自己有各自的特点,你只需要把他们的特点注入FactoryBean中,就可以生产出属于该类型的各种实例。
//定义类
@Data
public class Car {
private String carBrand; //汽车品牌
private String carPrice; //汽车价格
}
//具体创建对象过程
@Component
public class MyFactoryBean01 implements FactoryBean<Car> {
/**
* 当通过getBean获取一个FactoryBean时,返回的并不是FactoryBean本身,而是其创建的对象;
* 如果要获取FactoryBean对象本身,请在参数前面加一个&符号来获取。
*/
@Override
public Car getObject() throws Exception {
Car car = new Car();
car.setCarBrand("奔驰");
car.setCarPrice("999999");
return car;
}
/**
*获取对象的类型
*/
@Override
public Class<Car> getObjectType() {
return Car.class;
}
/**
*该Bean对象是否是单例模式
*/
@Override
public boolean isSingleton() {
return false;
}
}
//获取对象打印
@SpringBootTest
public class MyFactoryBean01Test {
@Autowired
private ApplicationContext applicationContext;
@Test
public void test01() throws Exception {
//调用getBean()方法获取Bean对象:
Object object = applicationContext.getBean("myFactoryBean01");
}
}
//输出
@Test
public void test01() throws Exception {
Object object = applicationContext.getBean("myFactoryBean01");
System.out.println("该对象的类型 = " + object.toString());
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9dujkM4y-1685513700973)(https://cdn.nlark.com/yuque/0/2022/png/400252/1666915803134-a3810bac-6283-4d32-9182-6359afe99f6a.png)]
3、总结
简单来说,BeanFactory提供基本的IOC和DI功能,而ApplicationContext提供高级功能,BeanFactory可用于测试和非生产使用,而ApplicationContext是功能更丰富的容器实现,应该更优于BeanFactory。
12、如何在spring前执行?
如果你使用Spring框架,在Spring容器初始化前执行一些操作,你可以通过实现ApplicationContextInitializer接口或使用@PostConstruct注解来实现。
- 使用ApplicationContextInitializer接口
你可以创建一个实现ApplicationContextInitializer接口的类,在该类中实现initialize()方法。在该方法中,你可以使用ConfigurableApplicationContext对象来执行初始化代码。例如:
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
//执行初始化代码
//例如:设置环境变量、启动定时任务等操作
}
}
然后,在Spring配置文件中,通过contextInitializerClasses属性来指定该类:
<ContextLoader listener>
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.example.MyApplicationContextInitializer</param-value>
</context-param>
</ContextLoader listener>
- 使用@PostConstruct注解
你可以在Spring Bean类中定义一个使用@PostConstruct注解的方法,在该方法中执行初始化操作。例如:
@Service
public class MyService {
@PostConstruct
public void init() {
//执行初始化代码
//例如:设置环境变量、启动定时任务等操作
}
}
当Spring容器创建该Bean时,会在所有依赖注入之后调用init()方法。
二、springboot总结
1、什么是Spring Boot,为什么要用?有哪些优点?
Spring Boot是对spring做简化,让开发从臃肿的配置中解脱出来。具体优点:简化开发、简化配置、易于部署.
2、Spring Boot常用注解有那些?
1、核心注解
Spring Boot的核心注解是
@SpringBootApplication
,它主要由以下三个注解组成:
@SpringBootConfiguration
:该注解标记一个Java类作为配置类来加载Spring的应用上下文,通常用于替换传统的XML配置文件。
@EnableAutoConfiguration
:借助于Spring框架的自动配置机制,自动扫描类路径下的Bean并加载到Bean容器中。开发者可以根据需要通过@Conditional
注解进行条件化自动配置。
@ComponentScan
:启用组件扫描机制,搜索指定包下的注解标记组件,并将它们加入Spring的应用上下文中。@EnableDiscoveryClient:
2、常用注解
@SpringBootApplication
:组合了@Configuration、@EnableAutoConfiguration和@ComponentScan注解,可用于标记应用程序的入口类。
@RestController
:自动将Spring MVC控制器中所有标注了@RequestMapping注解的方法返回的数据转换成JSON格式。
@Controller
:标识该类为Spring MVC控制器。
@RequestMapping
:将HTTP请求映射到控制器的处理方法上。
@RequestParam
:获取请求参数的值,将其绑定到控制器处理方法的参数上。
@PathVariable
:将一个URL中的参数绑定到控制器处理方法的参数上。
@Autowired
:自动装配,可用于标记对其他Bean的依赖注入。
@Component
:通用的注解,可用于标记类为Spring组件(Bean)。
@Service
:用于标记服务类。
@Repository
:用于标记数据访问层(DAO)类。
@Configuration
:用于标记配置类,该类中通常包含@Bean方法用于创建Bean对象。
@EnableAutoConfiguration
:启用Spring Boot的自动配置机制,可自动配置一些常用的Bean。
@Conditional
:条件化配置,根据一定的条件判断是否创建对应的Bean对象。
@Value
:获取配置文件中的属性值。
@Profile
:指定在特定环境下激活Bean。
@Autowired(required=false)
:当其他类不存在时也不会报错。
@Nullable
:标识该参数可以为null,放置参数未做校验。
@Resource
:按照名称进行注入,常用于注入静态变量。
@Qualifier
:指定具体要注入的Bean。
@Lazy
:懒加载,只有当该Bean被使用时才被创建。
@Async
:异步执行,将该方法标记为异步方法。
@Scheduled
:定时任务,用于标记在指定时间周期性执行的方法。
@Cacheable
:基于SpringCache实现缓存的注解。
@CachePut
:使方法执行后将结果缓存起来。
@CacheEvict
:清空缓存。
@Transactional
:用于标记需要在事务中执行的方法。
@EnableTransactionManagement
:启动事务管理。
@Valid
:数据校验,通常用于校验实体参数。
@NotNull
:该参数不允许为null。
@PathVariable
:将请求路径动态部分映射到方法参数上。
@RequestBody
:接收请求Body中的数据进行反序列化。
@RestControllerAdvice
:定义全局的异常处理器,可用于捕获处理全局异常。
@ExceptionHandler
:用于处理局部异常,通常与@RestControllerAdvice一起使用。
3、运行Spring Boot有哪几种方式
Spring Boot的应用程序一般有以下几种运行方式:
运行主类:在IDE中运行编写的Spring Boot应用程序的入口类,该入口类通常使用@SpringBootApplication注解标记,右键点击该类,选择Run或Debug即可启动应用程序。
使用Maven插件运行:通过Maven打包为JAR文件,在终端进入项目的根目录,执行
mvn spring-boot:run
即可启动应用程序。运行JAR文件:通过Maven将编写的Spring Boot应用程序打包为可执行的JAR文件,然后在终端中进入到目标文件夹下,运行命令
java -jar xxx.jar
即可启动应用程序。这种方式也是最常用的生产环境部署方式。
4、如何理解Spring Boot中的Starters?
1、java SPI
Java SPI(Service Provider Interface)是一种在 Java 平台上的接口技术,用于实现类似于插件的体系结构,通过在运行时动态地装载与动态获取后加载的实现类,来扩展系统的功能。SPI 使用了 Java 的服务加载机制,使得系统的扩展性变得非常灵活。Java SPI 的设计思想是 “面向接口编程”(Interface Programming),即与具体实现类相对,更关注于对接口或抽象类的编程。
在 Java SPI 中,开发者首先定义一个接口,然后编写若干个不同实现该接口的类,并将这些实现类打成 Jar 包,将 Jar 包中的 META-INF/services 文件夹下的实现类完全限定名放到该文件下(该文件名为接口全限定名),就完成了服务的注册。JDK 提供了 SPI 机制,只要将 Jar 包的路径放到系统 CLASSPATH 路径下,在运行时,使用 ServiceLoader.load(Class service) 方法即可返回该接口的所有实现类实例。
我们通过定义一个接口
HelloService
,然后创建两个实现类HelloServiceImpl1
和HelloServiceImpl2
,然后在 META-INF/services 目录下创建一个名为com.example.HelloService
的文件,在该文件中分别写入两个实现类的完全限定名,就可以使用ServiceLoader
来加载这些实现类。
- 接口
HelloService
的定义:public interface HelloService { void sayHello(); }
- 实现类
HelloServiceImpl1
:public class HelloServiceImpl1 implements HelloService { @Override public void sayHello() { System.out.println("Hello from HelloServiceImpl1"); } }
- 实现类
HelloServiceImpl2
:public class HelloServiceImpl2 implements HelloService { @Override public void sayHello() { System.out.println("Hello from HelloServiceImpl2"); } }
- 在 META-INF/services 目录下,创建文件
com.example.HelloService
,并写入实现类的完全限定名:com.example.HelloServiceImpl1 com.example.HelloServiceImpl2
- 在代码中使用
ServiceLoader
加载实现类:ServiceLoader<HelloService> loader = ServiceLoader.load(HelloService.class); for (HelloService helloService : loader) { helloService.sayHello(); }
通过上述代码,可以输出以下结果:
Hello from HelloServiceImpl1 Hello from HelloServiceImpl2
2、springboot start
Java SPI和spring start都是将一个实现功能接口化,方便用户配置方式选择不同的实现逻辑。
1、配置需要初始化bean的位置
在resource目录下新建META -INFO文件夹及spring.factories文件.并且指向实现配置类。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.test.demo.SpringbootConfig2、引入jar
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>2.2.6.RELEASE</version> </dependency>
3、新建被扫描进spring的bean
@Configuration public class SpringbootConfig { @Bean("HelloService") @ConditionalOnMissingBean // 找不到HelloService bean的时候通过该方法,初始化bean HelloService startService() { return new HelloServiceImpl(); } }
4、写好接口及实现类
@Configuration public class SpringbootConfig { @Bean("HelloService") @ConditionalOnMissingBean // 找不到HelloService bean的时候通过该方法,初始化bean HelloService startService() { return new HelloServiceImpl(); } } public class HelloServiceImpl implements HelloService { @Override public void sayHello() { System.out.println("hello my name is AAA"); } }
5、如何在Spring Boot启动的时候运行一些特定的代码?
Spring Boot提供了多种方式来在应用程序启动时运行一些特定的代码,下面列举其中几种常用的方式:
实现CommandLineRunner或ApplicationRunner接口:这两个接口都有一个run()方法,它们分别在应用程序启动完成后会自动被执行。可以在实现run()方法中编写特定的代码逻辑,例如初始化一些数据、配置一些定时任务等。
//ApplicationRunner启动监听 @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Bean public ApplicationRunner init() { return args -> { // 在这里添加需要在应用程序启动后执行的代码 }; } }
使用Spring的事件机制:Spring Boot中启动事件为ApplicationStartedEvent,可以通过监听该事件来在应用程序启动时执行特定的代码逻辑。只需要定义一个新的Spring Bean,并将其注解为@EventListener(ApplicationStartedEvent.class),然后在方法中编写需要执行的逻辑即可。
//springboot启动监听参数 @SpringBootApplication public class DemoApplication { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(DemoApplication.class, args); //在下面添加需要执行的初始化代码 } @EventListener public void handleContextRefreshed(ContextRefreshedEvent event) { ApplicationContext context = event.getApplicationContext(); //在下面添加需要在应用程序启动后执行的代码 } @EventListener public void handleApplicationFinished(ApplicationFinishedEvent event) { ApplicationContext context = event.getApplicationContext(); //在下面添加需要在应用程序退出前执行的代码 } }
启用Spring Boot的特定功能:Spring Boot提供了多个启动特定功能的注解,例如@PostConstruct、@Scheduled等。这些注解可以直接用在Spring Bean的方法上,当应用程序启动时自动执行相应的方法。
6、Spring Boot需要独立的容器运行吗?
spring Boot支持Tomcat、Jetty嵌入式容器,也可以把springboot应用达成war部署。
Spring Boot应用程序的打包方式默认是jar包,但是我们可以通过一些配置来将其打包为war包,以便于将应用程序部署到外部Web容器中。接下来,我将介绍如何将Spring Boot应用程序打包成war包。 1. 修改pom.xml文件 修改maven项目的pom.xml文件,并设置`<packaging>`元素的值为“war”,如下所示: <packaging>war</packaging> 2. 修改spring-boot-maven-plugin插件 将Spring Boot Maven插件替换为Web用例的插件,不再使用spring-boot-maven-plugin。除此之外,还需要添加Servlet-api和JSP-api的依赖。 <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servlet-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>${jsp-api.version}</version> <scope>provided</scope> </dependency> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>${maven-war-plugin.version}</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> 3. 添加启动类并配置启动方式 Spring Boot应用程序在war包中启动和在jar包中启动有所不同。在war包中,部署在外部Web容器中,因此需要在应用程序中添加启动类。该类需要扩展SpringBootServletInitializer类,并重写其configure()方法。configure()方法需要配置SpringApplication启动类。 public class ServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(DemoApplication.class); } } 4. 执行打包命令 mvn clean package 此时,会在项目的target目录下生成一个文件名为"[your-project-name].war"的war包。
7、Spring Boot中的监视器是什么?
1、Actuator监视器介绍
Spring Boot中的监视器(Spring Boot Actuator)是一个可选的模块,用于提供应用程序的健康状况、度量信息、日志记录、配置信息等功能。它可以帮助我们在实际部署应用程序时,掌控应用程序的状态与运行情况,可以通过HTTP、JMX、SSH等不同的方式对监视信息进行访问和管理。
监视器提供的功能包括但不限于:
- 健康监视:检查应用程序的健康状况,包括内存使用情况、线程数、数据库连接池状态等信息。
- 端点(Endpoints):提供访问应用程序内部结构的API,可用于查看和修改应用程序的状态和参数。
- 配置属性:显示应用程序所使用的配置属性和值。
- 日志记录:记录和/debugging日志输出配置。
Actuator默认已添加到Spring Boot项目中,对外提供了若干个端点,以暴露应用程序的运行状态信息。可以通过配置文件或代码来定制监视器的行为,使其符合自己的需求。例如,可以通过配置文件或代码来禁用某些端点,或修改默认设定的路径和请求方式。
2、如何禁用Actuator监视器
以下是禁用Actuator的几种方法:
- 在配置文件中禁用指定端点:在application.properties或者application.yml配置文件中,可以禁用指定端点,例如禁用health端点:
management.endpoint.health.enabled=false
。- 在配置文件中禁用所有端点:在application.properties或者application.yml配置文件中,可以使用
management.endpoints.enabled-by-default=false
来禁用所有的端点,然后根据需要显式启用需要的端点。- 在配置文件中禁用整个Actuator模块:在application.properties或者application.yml配置文件中,可以使用
management.endpoints.enabled=false
来全局禁用整个Actuator模块。- 在pom.xml文件中禁用Actuator依赖:在pom.xml文件中将
spring-boot-starter-actuator
依赖从项目中移除,或者将其排除(exclusion)即可禁用Actuator。
8、使用Spring Boot实现异常处理?
在Spring Boot应用程序中,我们可以通过自定义异常处理器来捕获并处理应用程序中的异常。以下是一些常见的异常处理方式:
- 基于@ControllerAdvice全局异常处理
在Spring Boot中,我们可以使用@ControllerAdvice注解来定义一个全局异常处理器,用于捕获和处理应用程序中抛出的所有异常。该注解的实际类型是@ExceptionHandler、@InitBinder和@ModelAttribute的集合,可以将这些注解所表示的方法应用于整个应用程序中,达到全局处理异常的目的。全局异常处理器的代码示例:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage());
}
}
- 基于@ExceptionHandler局部异常处理
除了使用@ControllerAdvice来定义全局异常处理器外,我们还可以在Controller层通过@ExceptionHandler注解定义局部异常处理器,只对当前Controller的方法有效。当方法抛出指定的异常时,会调用对应的处理方法。单个方法异常处理器的代码示例:
@RestController
public class UserController {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<String> handleNotFound(Exception ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
}
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
User user = userService.getUserById(id);
if (user == null) {
throw new ResourceNotFoundException("User not found with id " + id);
}
return user;
}
}
- 实现ErrorController接口错误处理
另一种处理Spring Boot应用程序中的异常的方法是实现ErrorController接口。实现该接口后,应用程序中的所有错误(包括404错误)都将被传递到实现类中。实现ErrorController接口的代码示例:
@RestController
public class CustomErrorController implements ErrorController {
private static final String PATH = "/error";
@RequestMapping(value = PATH)
public ResponseEntity<String> error() {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Custom 404 handling - page not found");
}
@Override
public String getErrorPath() {
return PATH;
}
}
4.自定义异常处理
此外我们每个公司可能有自己统一的自定义异常处理方式,以上的也可以不用。
9、SpringBoot 实现热部署有哪几种方式
在Spring Boot应用程序开发中,热部署是提高开发效率的重要方式。热部署可以使开发者无需重启应用程序,而实时更新修改后的代码并测试它们。在Spring Boot中,有几种实现热部署的方式:
- Spring Boot Devtools
Spring Boot Devtools是Spring Boot提供的一组工具,用于简化应用程序的开发和部署。其中包括了热部署的功能,只需要在POM文件中添加devtools依赖即可。Spring Boot Devtools会监听classpath下的文件变化,并自动重启应用程序。如果是开发Web应用程序,也可以让它自动更新静态资源,而无需重启应用程序。可以通过以下依赖添加到POM文件中来引入Spring Boot Devtools。 热部署需要开启配置:spring.devtools.restart.enabled=true,springboot自动监听文件变化自动加载。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
- 使用第三方插件
Spring Boot还支持使用第三方插件来实现热部署,常见的如JRebel和DCEVM。这些插件通常需要我们在开发时花费一些时间来进行配置。使用这些插件的好处是它们支持大多数Java框架和应用程序服务器,并且通常比Spring Boot Devtools更快。
- 结合Gradle、Maven等构建工具来实现
使用Gradle、Maven等构建工具来实现热部署也是一种方法。这些工具可以帮助我们在代码变化时重新编译和重载类文件。但是,这种方法需要先运行构建命令,然后手动重启应用程序,在开发效率方面略微低于其他两种方法。
总之,Spring Boot提供了多种方式来实现热部署,可以根据实际需求选择相应的方式。在开发过程中,合理使用热部署工具能够大大提高开发效率。
10、如何理解Spring Boot配置加载顺序
在Spring Boot中,有多种方式来配置应用程序。这样就涉及到了Spring Boot配置加载的顺序。Spring Boot根据预定的顺序来加载配置,具体顺序如下:
- 命令行参数
命令行参数总是具有最高优先级,可以通过命令行参数来覆盖任何其他配置。例如:
java -jar myproject.jar --server.port=8080
- Java系统属性
Spring Boot还支持使用Java系统属性来配置应用程序的设置, 例如:
java -jar -Dserver.port=8080 myproject.jar
3. 操作系统环境变量
您也可以在操作系统环境中设置属性,Spring Boot会自动将它们读取并转换为Spring Environment属性。例如,在Linux下,这可以通过设置环境变量来实现:
$ export SPRING_APPLICATION_JSON='{"name":"value"}'
$ java -jar myproject.jar
- 指定的“application.properties”或“application.yml”文件,可以根据环境dev、test、prod指定
除了随机生成的文件之外,您也可以显式地提供一个特定的application.properties或application.yml文件。例如,通过以下方式制定:
java -jar myproject.jar --spring.config.name=myproject --spring.config.location=/app/config/
11、Spring Boot的核心配置文件优先级?
Spring Boot的核心配置文件有以下几个:
- bootstrap.properties
bootstrap.properties文件是Spring Boot应用程序启动的第一个文件,用于配置Spring Boot上下文的创建。该文件的加载早于application.properties,可以用于配置一些基本的系统属性,如Spring Cloud的配置文件等。
bootstrap.properties主要用于配置一些与Spring Boot上下文相关的配置信息,如Spring Cloud Config Server的URL地址等。它也是一个标准的.properties文件,支持与application.properties相同的配置属性。
这三个配置文件之间的区别主要在于格式和加载的优先级。其中,bootstrap.properties的优先级最高,而application.yml的优先级最低。一般情况下,我们可以通过application.properties和application.yml文件来进行配置。如果需要更高的优先级,可以使用bootstrap.properties文件。
- application.properties 、application.yml
application.properties是Spring Boot常用的配置文件之一,是一个命名为application的标准.properties文件,使用key=value的键值对形式,用于配置Spring Boot应用程序的属性。
application.yml是另一种常用的配置文件,它使用了更加人性化的YAML格式,以树形结构表示属性和属性的值,相对比较易于阅读和理解。但是yml使用体验不如application.properties,要对齐文件可能产生莫名其妙的问题。
12、什么是JavaConfig?
JavaConfig就是使用注释来描述Bean配置的组件。一般使用@Bean注释。
@Configuration public class AppConfig { //注入bean @Bean public MyService myService() { return new MyServiceImpl(); } }
13、如何重新加载Spring Boot上的更改, 而无需重新启动服务器?
1.使用devtools热加载模块
2.使用动态修改配置加载配置的方式,执行不同逻辑分支。
14、Spring Boot 中定义Tomcat参数
在Spring Boot中,可以配置以下常见的Tomcat参数,附带中文注释:
# 最大请求连接队列长度,当所有的请求处理线程都在使用时,所有的来自客户端的请求连接会放在队列中排队等待处理。 server.tomcat.accept-count= # 是否将访问日志直接写入文件,还是使用缓冲区。 server.tomcat.accesslog.buffered=true # 日志文件所在目录,可以是相对路径或者绝对路径。 server.tomcat.accesslog.directory=logs # 是否开启访问日志。 server.tomcat.accesslog.enabled=false # 日志文件名格式的日期格式。 server.tomcat.accesslog.file-date-format=.yyyy-MM-dd # 访问日志格式。 server.tomcat.accesslog.pattern=common # 日志文件名前缀。 server.tomcat.accesslog.prefix=access_log # 是否在轮换时间之前延迟日志文件名后添加日期和时间戳。 server.tomcat.accesslog.rename-on-rotate=false # 是否设置请求属性,用于记录请求的IP地址、主机名、协议和端口号。 server.tomcat.accesslog.request-attributes-enabled=false # 是否启用访问日志轮换。 server.tomcat.accesslog.rotate=true # 日志文件名后缀。 server.tomcat.accesslog.suffix=.log # 是否压缩旋转的日志文件。 server.tomcat.accesslog.use-gzip=false # 用于TLD扫描的额外排除jar包的匹配模式,用英文逗号(,)分隔。 server.tomcat.additional-tld-skip-patterns= # 调用backgroundProcess方法之间的延迟时间,单位是秒。 server.tomcat.background-processor-delay=30 # Tomcat的基目录,如果未指定,则将其默认设置为临时目录。 server.tomcat.basedir= # 受信任的IP地址的正则表达式,用于过滤请求头中的X-Forwarded-For和X-Real-IP属性,可以自定义。 server.tomcat.internal-proxies=10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|\\ 192\\.168\\.\\d{1,3}\\.\\d{1,3}|\\ 169\\.254\\.\\d{1,3}\\.\\d{1,3}|\\ 127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|\\ 172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|\\ 172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|\\ 172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3} # 处理器连接数池中保持的最大连接数。 server.tomcat.max-connections= # 允许的最大HTTP表单post大小,以字节为单位。 server.tomcat.max-http-form-post-size= # 最大HTTP头大小,以字节为单位。 server.tomcat.max-http-header-size= # 最大线程池大小。 server.tomcat.max-threads= # 是否在重定向时自动重置缓冲区。 server.tomcat.redirect-context-root= # 重定向时,是否发送HTTP响应状态。 server.tomcat.redirect-context-root-http-status-code= # 在URI解码期间使用的编码。 server.tomcat.uri-encoding= # 是否启用HTTP2协议。 server.http2.enabled= # 使用JSSE处理程序时,是否支持SSL协议的SessionTickets。 server.ssl.session-ticket.enabled= # 是否启用SSL协商的Ciphersuite黑名单,如果启用,请指定要使用的黑名单算法。 server.ssl.ciphersuites-blacklist-enabled= # 指定SSL协商的Ciphersuite黑名单算法。 server.ssl.ciphersuites-blacklist= # SSL协商的Ciphersuite白名单。 server.ssl.ciphersuites= # SSL协商的Ciphersuite白名单,默认情况下启用。 server.ssl.ciphersuites-enabled= # SSL配置的密
2、通过javaConfig方式加载参数
可以使用Java配置类来加载并配置Tomcat参数。例如:@Configuration public class TomcatConfig { @Value("${server.tomcat.max-connections}") private int maxConnections; @Value("${server.tomcat.uri-encoding}") private String uriEncoding; @Bean public TomcatServletWebServerFactory tomcatFactory() { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); factory.setProtocol("org.apache.coyote.http11.Http11NioProtocol"); factory.addConnectorCustomizers(connector -> { Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler(); protocol.setMaxConnections(maxConnections); protocol.setConnectionTimeout(60000); connector.setURIEncoding(uriEncoding); }); return factory; } }
23、如何实现Spring Boot应用程序的安全性?
为了确保Spring Boot应用程序的安全性,可以采取以下措施:
- 使用HTTPS协议
使用HTTPS协议可以加密应用程序与客户端之间的通信,并防止中间人攻击。可以使用Spring Boot提供的自动配置特性对HTTPS进行配置,例如:
server.port=8443 server.ssl.key-store-type=PKCS12 server.ssl.key-store=classpath:keystore.p12 server.ssl.key-store-password=changeme server.ssl.key-alias=tomcat
- 安全管理端点
Spring Boot的Actuator模块提供了许多用于监控和管理应用程序的端点,这些端点包含了一些敏感信息,例如/health端点可以显示应用程序的健康状态。为了限制对这些端点的访问,可以进行如下配置:
management.endpoints.web.exposure.include=info,health management.endpoint.health.show-details=never management.endpoints.jmx.exposure.exclude=*
上述配置表示只公开info和health端点,不显示health的详细信息,同时禁用所有JMX端点。
- 使用安全框架
可以使用Spring Security或其他安全框架来保护应用程序的资源和端点。Spring Security提供了诸如身份验证、授权、会话管理、密码保护等功能,可以使用注解或XML配置来定义安全策略。
- 使用安全编码规范
开发者需要采用安全的编码实践,例如避免在代码中硬编码密码等敏感信息、使用加密算法等,以防止被黑客攻击。可以使用一些自动化工具来帮助开发者检查和修复潜在的安全漏洞,例如OWASP Dependency Check、SonarQube、FindBugs等。
- 为应用程序配置正确的权限
为应用程序的每个角色分配相应的权限,例如仅分配必要的数据库访问权限
- 加强日志记录
正确配置应用程序的日志记录可以识别入侵尝试和防止安全漏洞,例如记录重要事件、错误和异常、指定哪些入侵尝试应该被记录下来等。Spring Boot的Actuator端点提供了轻松实现记录的便利方式。
、如何实现Spring Boot应用程序的安全性?
为了确保Spring Boot应用程序的安全性,可以采取以下措施:
- 使用HTTPS协议
使用HTTPS协议可以加密应用程序与客户端之间的通信,并防止中间人攻击。可以使用Spring Boot提供的自动配置特性对HTTPS进行配置,例如:
server.port=8443 server.ssl.key-store-type=PKCS12 server.ssl.key-store=classpath:keystore.p12 server.ssl.key-store-password=changeme server.ssl.key-alias=tomcat
- 安全管理端点
Spring Boot的Actuator模块提供了许多用于监控和管理应用程序的端点,这些端点包含了一些敏感信息,例如/health端点可以显示应用程序的健康状态。为了限制对这些端点的访问,可以进行如下配置:
management.endpoints.web.exposure.include=info,health management.endpoint.health.show-details=never management.endpoints.jmx.exposure.exclude=*
上述配置表示只公开info和health端点,不显示health的详细信息,同时禁用所有JMX端点。
- 使用安全框架
可以使用Spring Security或其他安全框架来保护应用程序的资源和端点。Spring Security提供了诸如身份验证、授权、会话管理、密码保护等功能,可以使用注解或XML配置来定义安全策略。
- 使用安全编码规范
开发者需要采用安全的编码实践,例如避免在代码中硬编码密码等敏感信息、使用加密算法等,以防止被黑客攻击。可以使用一些自动化工具来帮助开发者检查和修复潜在的安全漏洞,例如OWASP Dependency Check、SonarQube、FindBugs等。
- 为应用程序配置正确的权限
为应用程序的每个角色分配相应的权限,例如仅分配必要的数据库访问权限
- 加强日志记录
正确配置应用程序的日志记录可以识别入侵尝试和防止安全漏洞,例如记录重要事件、错误和异常、指定哪些入侵尝试应该被记录下来等。Spring Boot的Actuator端点提供了轻松实现记录的便利方式。