Spring
IOC(控制反转):无需创建对象,而是通过Spring框架自动创建
DI(依赖注入):通过构造函数/setter方法/属性注入,将属性数据初始化.
AOP(面向切面编程): 针对相同功能的封装,无需针对不同的对象,写2遍代码。把应用业务逻辑和系统服务分开。
Spring 架构
Spring 常用注解
@Controller - 用于 Spring MVC 项目中的控制器类。
@Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。
@Service - 是@Component 注解的特化,用于服务类。
@Repository:是@Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。
@RequestMapping - 用于在控制器处理程序方法中配置 URI 映射。
@ResponseBody - 用于发送 Object 作为响应,通常用于发送 XML 或 JSON 数据作为响应。
@PathVariable - 用于将动态值从 URI 映射到处理程序方法参数。
@Autowired - 用于在 spring bean 中自动装配依赖项。
@Qualifier - 使用 @Autowired 注解,以避免在存在多个 bean 类型实例时出现混淆。在同一类型的bean有多个的情况下可以实现根据name注入的需求
@Scope - 用于配置 spring bean 的范围。
@Configuration,@ComponentScan 和 @Bean - 用于基于 java 的配置。
@Aspect,@Before,@After,@Around,@Pointcut - 用于切面编程(AOP)
@Required 注解:应用于 bean 属性 setter 方法。此注解仅指示必须在配置时使用 bean 定义中的显式属性值或使用自动装配填充受影响的 bean 属性。如果尚未填充受影响的 bean 属性,则容器将抛出BeanInitializationException
helloworld示例
package com.tutorialspoint;
public class HelloWorld {
private String message;
public void setMessage(String message){
this.message = message;
}
public void getMessage(){
System.out.println("Your Message : " + message);
}
}
package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(“Beans.xml”);
HelloWorld obj = (HelloWorld) context.getBean(“helloWorld”);
obj.getMessage();
}
}
bean.xml
beans的数据类型
list:作用域从单例改为原型
set:作用域从单例改为原型
map:类型用于注入一组键值对,键和值都可以为任意类型
props:类型用于注入一组键值对,键和值都只能为String类型。
bean的作用域(常考点)
beans.xml的scope参数
作用域 描述
singleton 将 bean 定义范围限定为每个 Spring IoC 容器的单个实例(默认)。
prototype 将单个 bean 定义的范围限定为具有任意数量的对象实例。如果作用域设置为prototype,则每次对特定 bean 发出请求时,Spring IoC 容器都会创建对象的新 bean 实例。 通常,对所有状态完整的 bean 使用 prototype 作用域,对无状态 bean 使用 singleton 作用域。
request 在请求 bean 范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后, bean会失效并被垃圾回收器回收 。
session 将 bean 定义范围限定为 HTTP 会话。 在 session 过期后, bean 会随之失效
global-session 和 Portlet 应用相关 。 当你的应用部署在 Portlet 容器中工作时,它包含很多 portlet。 如果你想要声明让所有的 portlet 共用全局的存储变量的话,那么这全局变量需要存储在 global-session 中
Bean的回调方法
BeanPostProcessor 接口完成它们的工作。
ApplicationContext 会自动检测任何通过 BeanPostProcessor 接口的实现定义的 bean,并将这些 bean 注册为 postprocessors,然后在 bean 创建时由容器适当地调用。
package com.tutorialspoint;
public class HelloWorld {
private String message;
public void setMessage(String message){
this.message = message;
}
public void getMessage(){
System.out.println("Your Message : " + message);
}
public void init(){
System.out.println(“Bean is going through init.”);
}
public void destroy(){
System.out.println(“Bean will destroy now.”);
}
}
在初始化bean之前调用的函数,在销毁bean之后调用的函数
package com.tutorialspoint;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;
public class InitHelloWorld implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("BeforeInitialization : " + beanName);
return bean; // you can return any other object as well
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("AfterInitialization : " + beanName);
return bean; // you can return any other object as well
}
}
package com.tutorialspoint;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext(“Beans.xml”);
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
context.registerShutdownHook();
}
}
beans.xml
import org.springframework.beans.factory.annotation.Required;
public class Student {
private Integer age;
private String name;
@Required
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
@Required
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
以下是 MainApp.java 文件的内容 −
package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(“Beans.xml”);
Student student = (Student) context.getBean("student");
System.out.println("Name : " + student.getName() );
System.out.println("Age : " + student.getAge() );
}
}
context:annotation-config/
@Autowired 注解可以应用于 bean 属性设置方法、非设置方法、构造函数和属性。避免在beans.xml中配置 @Autowired(required=true),表示注入的时候,该bean必须存在,否则就会注入失败。 @Autowired(required=false):表示忽略当前要注入的bean,如果有直接注入,没有跳过,不会报错。 @Qualifier @Qualifier 注解和@Autowired 可用于通过指定将被连接的确切bean 来消除混淆。当您创建多个相同类型的 bean 并希望仅将其中一个与属性关联时,可能会出现这种情况。 在这种情况下,您可以将 @Qualifier 注解与 @Autowired 一起使用,通过指定要连接的确切 bean 来消除混淆。 //Student.java file package com.tutorialspoint;public class Student {
private Integer age;
private String name;
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Profile.java
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Profile {
@Autowired
@Qualifier(“student1”)//Autowired和Qualifier结合使用。获取beans.xml中的注解,student1的属性参数
private Student student;
public Profile(){
System.out.println(“Inside Profile constructor.” );
}
public void printAge() {
System.out.println("Age : " + student.getAge() );
}
public void printName() {
System.out.println("Name : " + student.getName() );
}
}
//MainApp.java
package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(“Beans.xml”);
Profile profile = (Profile) context.getBean("profile");
profile.printAge();
profile.printName();
}
}
// Beans.xml
context:annotation-config/
JSR-250 注解 Spring 支持基于 JSR-250 的注解,其中包括 @Resource、@PostConstruct 和 @PreDestroy 注解。 基于java的配置 使用 @Configuration 注解一个类表明该类可以被 Spring IoC 容器用作 bean 定义的来源。 @Bean 注解告诉 Spring使用 @Bean 注解的方法将返回一个对象,该对象应在 Spring 应用程序上下文中注册为 bean。 @Import 注解允许从另一个配置类加载@Bean 定义。 Eg: @Configuration public class ConfigA { @Bean public A a() { return new A(); } } @Configuration @Import(ConfigA.class) public class ConfigB { @Bean public B b() { return new B(); } } public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);// now both beans A and B will be available…
A a = ctx.getBean(A.class);
B b = ctx.getBean(B.class);
}
AOP(常考点)
OOP 中模块化的关键单元是类,而 AOP 中模块化的单元是切面。 依赖注入可帮助您将应用程序对象彼此分离,而 AOP 可帮助您将横切关注点与它们影响的对象分离。
AOP 术语
1、切面(Aspect):被抽取的公共模块(日志,控制权限等功能),可能会横切多个对象。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。是一个可以定义切点、各类通知和引入的内容,SpringAOP将通过它的信息来增强Bean的功能或者将对应的方法织入流程。
2、连接点(Join point):指具体方法,在Spring AOP中,一个连接点 总是 代表一个方法的执行。
3、通知(Advice):在切面的某个特定的连接点(Join point方法)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。
4、切入点(Pointcut):对多个连接点的拦截操作。有时候,我们的切面不单单应用于单个方法(连接点),也可能是多个类的不同方法,这时,可以通过正则式和指示器的规则去定义,从而适配连接点。切入点是指 我们要对哪些Join point进行拦截的定义。通过切入点表达式,指定拦截的方法,比如指定拦截add、search。
5、引入(Introduction):(也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。
6、目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(adviced) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。
7、织入(Weaving):指把增强应用到目标对象来创建新的代理对象的过程。Spring是在运行时完成织入。
切入点(pointcut)和连接点(join point)匹配的概念是AOP的关键,这使得AOP不同于其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次。 例如,一个提供声明式事务管理的around通知可以被应用到一组横跨多个对象中的方法上(例如服务层的所有业务操作)。
AOP与OOP
AOP(Aspect-OrientedProgramming,面向方面编程):是OOP的补充和完善。OOP引入了封装、继承、多态性等建立一种对象层次结构(从上到下的关系)。当需要为分散的对象引入公共行为的时候(从左到右的关系),OOP就显得无能为力。例如:日志功能。日志代码往往水平的散布在所有对象层次中,与对象的核心功能毫无关系。这种代码被称为横切(cross-cutting)代码还有像安全性、异常处理、透明的持续性等都称为横切代码。在OOP设计中,它们导致了大量代码的重复,不利于模块的重用。
AOP与OOP相反,利用“横切”技术将影响多个类的公共行为封装到一个可重用模块,称为Aspect。简单点,就是将那些与业务无关,却被业务模块所共同调用的逻辑封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。” Spring提供了两种方式生成代理对象:JDKProxy和Cglib具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。
Spring JDBC示例
编写一个简单的CRUD
SQL语句,增删改查
CREATE TABLE Student(
ID INT NOT NULL AUTO_INCREMENT,
NAME VARCHAR(20) NOT NULL,
AGE INT NOT NULL,
PRIMARY KEY (ID)
);
package com.tutorialspoint;
import java.util.List;
import javax.sql.DataSource;
public interface StudentDAO {
/**
* This is the method to be used to initialize
* database resources ie. connection.
*/
public void setDataSource(DataSource ds);
/**
* This is the method to be used to create
* a record in the Student table.
*/
public void create(String name, Integer age);
/**
* This is the method to be used to list down
* a record from the Student table corresponding
* to a passed student id.
*/
public Student getStudent(Integer id);
/**
* This is the method to be used to list down
* all the records from the Student table.
*/
public List listStudents();
/**
* This is the method to be used to delete
* a record from the Student table corresponding
* to a passed student id.
*/
public void delete(Integer id);
/**
* This is the method to be used to update
* a record into the Student table.
*/
public void update(Integer id, Integer age);
}
spring事务管理
等同于数据库的事务管理(ACID)
原子性 − 事务应被视为单个操作单元,这意味着整个操作序列要么成功,要么不成功。
一致性 − 这代表了数据库的引用完整性、表中唯一主键等的一致性。
隔离性 − 一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
持续性 − 也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
声明式事务管理优于程序式事务管理,尽管它不如程序式事务管理灵活,后者允许您通过代码控制事务。 但是作为一种横切关注点,声明式事务管理可以使用 AOP 方法进行模块化。 Spring 通过 Spring AOP 框架支持声明式事务管理。
以下是隔离级别的可能值 −
无法复制加载中的内容
Spring mvc
C->M->V
通过Controller选择合适的Model,Model将处理后的数据返回给View
以下是对应于 DispatcherServlet 的传入 HTTP 请求的事件序列 −
接收到一个HTTP请求后,DispatcherServlet咨询HandlerMapping来调用合适的Controller。
Controller 接受请求并根据使用的 GET 或 POST 方法调用适当的服务方法。 服务方法将根据定义的业务逻辑设置模型数据并将视图名称返回给DispatcherServlet。
DispatcherServlet 将从 ViewResolver 获取帮助以获取请求的定义视图。
一旦视图最终确定,DispatcherServlet 将模型数据传递给视图,最终在浏览器上呈现。
上述所有组件,即 HandlerMapping、Controller 和 ViewResolver 都是 WebApplicationContext 的一部分,它是普通 ApplicationContext 的扩展,具有 Web 应用程序所需的一些额外功能。
以下是关于 HelloWeb-servlet.xml 文件的要点 −
[servlet-name]-servlet.xml 文件将用于创建定义的 bean,覆盖在全局范围内以相同名称定义的任何 bean 的定义。
context:component-scan... 标签将用于激活 Spring MVC 注解扫描功能,允许使用 @Controller 和 @RequestMapping 等注解。
InternalResourceViewResolver 将定义用于解析视图名称的规则。 根据上面定义的规则,名为 hello 的逻辑视图被委托给位于 /WEB-INF/jsp/hello.jsp 的视图实现。
以下部分将向您展示如何创建您的实际组件,即控制器、模型和视图。
定义控制器
DispatcherServlet 将请求委托给控制器以执行特定于它的功能。
@Controller 注解将类定义为 Spring MVC 控制器,可以同时支持处理多个请求动作,使程序开发变的更加灵活。controller接口只能处理单一的动作。 这里,@RequestMapping 的第一个用法表示该控制器上的所有处理方法都是相对于 /hello 路径的。可以同时支
持处理多个请求动作,使程序开发变的更加灵活。
@RequestMapping(method = RequestMethod.GET) 用于将 printHello() 方法声明为控制器的默认服务方法来处理 HTTP GET 请求。您可以定义另一种方法来处理同一 URL 处的任何 POST 请求。
@Controller
public class HelloController {
@RequestMapping(value = “/hello”, method = RequestMethod.GET)
public String printHello(ModelMap model) {
model.addAttribute(“message”, “Hello Spring MVC Framework!”);
return “hello”;
}
}
value 属性指示处理程序方法映射到的 URL,method 属性定义处理 HTTP GET 请求的服务方法。 关于上面定义的控制器,需要注意以下几点 −
您将在服务方法中定义所需的业务逻辑。 您可以根据需要在该方法中调用另一个方法。
根据定义的业务逻辑,您将在此方法中创建一个模型。 您可以使用 setter 不同的模型属性,视图将访问这些属性以呈现最终结果。 这个例子创建了一个具有"message"消息属性的模型。
定义的服务方法可以返回一个字符串,其中包含要用于渲染模型的视图名称。 此示例返回"hello"作为逻辑视图名称。
尝试访问 URL http://localhost:8080/HelloWeb/hello 如果您的 Spring Web 应用程序一切正常,您应该会看到以下结果
您应该注意,在给定的 URL 中,HelloWeb 是应用程序名称,hello 是我们在控制器中使用 @RequestMapping(“/hello”) 提到的虚拟子文件夹。您可以在使用 @RequestMapping(“/”) 映射 URL 时使用直接 root。在这种情况下,您可以使用短 URL http://localhost:8080/HelloWeb/ 访问相同的页面,但建议在不同的文件夹下具有不同的功能。
AOP与IOC
1、@Controller:用于标注控制器层组件
2、@Service:用于标注业务层组件
3、@Component : 用于标注这是一个受 Spring 管理的组件,组件引用名称是类名,第一个字母小写。可以使用@Component(“beanID”) 指定组件的名称
4、@Repository:用于标注数据访问组件,即DAO组件
5、@Bean:方法级别的注解,主要用在@Configuration和@Component注解的类里,@Bean注解的方法会产生一个Bean对象,该对象由Spring管理并放到IoC容器中。引用名称是方法名,也可以用@Bean(name = “beanID”)指定组件名
6、@Scope(“prototype”):将组件的范围设置为原型的(即多例)。保证每一个请求有一个单独的action来处理,避免action的线程问题。
由于Spring默认是单例的,只会创建一个action对象,每次访问都是同一个对象,容易产生并发问题,数据不安全。
7、@Autowired:默认按类型进行自动装配by-type。在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。
8、@Resource:默认按名称进行自动装配,by-name,当找不到与名称匹配的Bean时会按类型装配。
Restful
1.当您知道要创建或覆盖的内容的URL时,应该使用PUT方法。PUT API URL 是: http://localhost:8080/products/3
2.当您只知道要创建内容的对象的类别或子部分的URL,请使用POST方法。POST API URL 是: http://localhost:8080/products
拦截器
以下是您在使用拦截器时应该了解的三种方法 −
step1:preHandle() 方法 − 这用于在将请求发送到控制器之前执行操作。 此方法应返回 true 以将响应返回给客户端。
step2:postHandle() 方法 − 这用于在向客户端发送响应之前执行操作。
step3:afterCompletion() 方法 − 这用于在完成请求和响应后执行操作。
Spring boot
Springboot配置加载顺序
https://blog.csdn.net/zxd1435513775/article/details/103773404
1、项目内配置文件加载顺序
SpringBoot项目启动会扫描以下位置的application.properties或者application.yml文件作为SpringBoot的默认配置文件,具体的目录位置见下图。
file:./config/ ( 项目根路径下的config文件夹)
file:./ (项目根路径)
classpath:/config/ (类路径下的config文件夹)
classpath:/ (类路径)
上面四个位置的配置文件位置,优先级由高到低,高优先级的配置会覆盖低优先级的配置,没有的配置进行互补配置。
注意:不是类路径下的配置文件在打包时,如果不做配置是不会打包进jar中的,也就是说前两个配置在项目打包后,包中是不存在的,所以尽量不要用前两个位置。
2.外部配置文件
1)项目打包好以后,我们可以使用命令行参数的形式,来改变想改变的几个参数,直接在启动命令后添加启动参数,如果有多个配置项,可以用空格分开。
java -jar springboot-configuration.jar --server.port=8088 --server.servlet.context-path=/spring
2)如果配置参数太多,可以考虑引用外部文件
指定配置文件从F盘下读取
java -jar springboot-configuration.jar --spring.config.location=F:/application.properties
3)加载顺序
命令行参数。所有的配置都可以在命令行上进行指定;
来自java:comp/env的JNDI属性;
Java系统属性(System.getProperties());
操作系统环境变量 ;
jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件
jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件 再来加载不带profile
jar包外部的application.properties或application.yml(不带spring.profile)配置文件
jar包内部的application.properties或application.yml(不带spring.profile)配置文件
@Configuration注解类上的@PropertySource
SpringBoot 核心配置
Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。
application 配置文件这个容易理解,主要用于 Spring Boot 项目的自动化配置。
bootstrap 配置文件有以下几个应用场景。
1)使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的
配置属性来加载外部配置中心的配置信息;
2)一些固定的不能被覆盖的属性;
3)一些加密/解密的场景;
SpringBoot核心注解
启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下3 个注解:
1)@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
2)@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
3)@ComponentScan:Spring组件扫描
Spring & SpringBoot常用注解
@SpringBootApplication:
创建 SpringBoot 项目之后会默认在主类加上。我们可以把 @SpringBootApplication 看作是 @Configuration 、 @EnableAutoConfiguration 、@ComponentScan 注解的集合。
@EnableAutoConfiguration :启用 SpringBoot 的自动配置机制
@ComponentScan : 扫描被@Component(@service,@controller)注解的bean,注解会默认扫描包下的所有的类
@Configuration:允许Spring上下文中注册额外的bean或者导入其他配置类
Spring Bean相关
1.@Autowired:自动导入对象到类中,被注入进的类同样要被 Spring 容器管理比如:Service 类注入到 Controller 类中
2.@Component, @Repository, @Service, @Controller,组合到一起,可以实现@Autowired
@Component :通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用 @Component 注解标注。
@Repository : 对应持久层即 Dao 层,主要用于数据库相关操作
@Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。
@Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。
1.@RestController:是 @Controller和 @ ResponseBody 的合集,表示这是个控制器 bean,并且是将函数的返回值直接填入 HTTP 响应体中,是 REST 风格的控制器。
2.@Configuration:一般用来声明配置类,可以使用 @Component 注解替代,不过使用 @Configuration 注解声明配置类更加语义化
常见HTTP请求类型
GET :请求从服务器获取特定资源。举个例子: GET /users (获取所有学生)
POST :在服务器上创建一个新的资源。举个例子: POST /users (创建学生)
PUT :更新服务器上的资源(客户端提供更新后的整个资源)。举个例子: PUT /users/12 (更新编号为 12 的学生)
DELETE :从服务器删除特定的资源。举个例子: DELETE /users/12 (删除编号为 12 的学生)
PATCH :更新服务器上的资源(客户端提供更改的属性,可以看做作是部分更新),使用的比较少,这里就不举例子了。
前后端传值
将前端的请求传递给后端服务。
1.@PathVariable 用于获取路径参数。@RequestParam 用于获取查询参数
@GetMapping(“/klasses/{klassId}/teachers”)
public List getKlassRelatedTeachers(
@PathVariable(“klassId”) Long klassId,
@RequestParam(value = “type”, required = false) String type ) {
…
}
如果我们请求的 url 是: /klasses/{123456}/teachers?type=web
那么我们服务获取到的数据就是: klassId=123456,type=web 。
1.@RequestBody:用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分并且Content-Type 为application/json 格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上去。
将json报文中的username,fullname,password赋值给变量
Spring 全家桶各种注解汇总
https://blog.csdn.net/liuerchong/article/details/118242460
1.resource和autowired的区别
@Autowired默认按照by-Type方式进行bean匹配,@Resource默认按照by-Name方式进行bean匹配
@Autowired是Spring的注解,@Resource是J2EE的注解
@ResponseBody
加了这个注解的类会将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML。
@RestController = @Controller + @ResponseBody
1.SpringBootApplication
@SpringBootApplication是一个复合注解,包含了@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan这三个注解。
@ComponentScan(“com.demo”) 引号里面是要扫描的包路径
@SpringBootApplication这个注解里面集成了@ComponentScan注解,它里面会自动扫描这个类所在包以及子包下面的bean。
所以如果我们要找的bean不在它的所在包或者子包里面,就需要自己再添加一个@ComponentScan注解。例如:
@ComponentScan({“com.demo.springboot”,”com.demo.somethingelse”})
1.
@ImportResource(locations={}) 导入其他xml配置文件,需要标准在主配置类上。
导入property的配置文件 @PropertySource指定文件路径,这个相当于使用spring的标签来完成配置项的引入。
@import注解是一个可以将普通类导入到spring容器中做管理
@CrossOrigin:@CrossOrigin(origins = “”, maxAge = 1000) 这个注解主要是为了解决跨域访问的问题。这个注解可以为整个controller配置启用跨域,也可以在方法级别启用。
SpringCloud
1.熔断与服务降级
熔断:当某服务出现不可用或响应超时的情况时,直接返回服务不可用状态,无需发送请求
服务降级:是从整个系统的负荷情况出发和考虑的,对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况,在其内部暂时舍弃对一些非核心的接口和数据的请求,而直接返回一个提前准备好的fallback(退路)错误处理信息。先发送服务请求,然后再返回服务不可用的状态
https://zhuanlan.zhihu.com/p/446563641
NGINX
1.正向代理与反向代理
正向代理就是一个人发送一个请求直接就到达了目标的服务器
反方代理就是请求统一被Nginx接收,nginx反向代理服务器接收到之后,按照一定的规则分发给了后端的业务处理服务器进行处理了
反向代理服务器可以隐藏源服务器的存在和特征。它充当互联网云和web服务器之间的中间层。这对于安全方面来说是很好的,特别是当您使用web托管服务时。
1.nginx性能高的原因:异步非阻塞事件处理机制:运用了epoll模型,提供了一个队列,排队解决
2.nginx负载均衡策略
1.轮询(默认),按照配置,从前到后轮询
upstream backserver {
server 192.168.0.12;
server 192.168.0.13;
}
1.权重配置。weight的值越大分配
u
pstream backserver {
server 192.168.0.12 weight=2;
server 192.168.0.13 weight=8;
}
1.ip_hash( IP绑定):每个请求按访问IP的哈希结果分配,使来自同一个IP的访客固定访问一台后端服务器,并且可以有效解决动态网页存在的session共享问题
upstream backserver {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
刷题与知识点整理
Spring解析
题目1:
链接:https://www.nowcoder.com/questionTerminal/3b5ceddff6a74ef990d2144605f860f2
来源:牛客网
A 在spring中有两种事务的实现方式,分别是编程式事务管理和编码式事务管理。
编程式事务一般使用的是TransactionTemplate工具类来实现
spring中使用的是@Transactional注解,可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性。
参数描述:
readOnly 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
rollbackFor 该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
rollbackForClassName 该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:指定单一异常类名称@Transactional(rollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”})
noRollbackFor 该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
noRollbackForClassName 该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”})
propagation 该属性用于设置事务的传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
isolation 该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
timeout 该属性用于设置事务的超时秒数,默认值为-1表示永不超时
我们可以使用propagation 来对事务的传播行为进行声明式的设定
类型
REQUIRED 如果方法运行时,已经处在一个事务中,那么加入到这个事务,否则自己新建一个新的事务。
NOT_SUPPORTED 声明方法不需要事务。
如果方法没有关联到一个事务,容器不会为他开启事务,
如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行
REQUIRESNEW 不管是否存在事务,该方法总是为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。
MANDATORY 该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出例外。
SUPPORTS 该方法在某个事务范围内被调用,则方法成为该事务的一部分。如果方法在该事务范围外被调用,该方法就在没有事务的环境下执行。
NEVER 该方法绝对不能在事务范围内执行。如果在就抛例外。只有该方法没有关联到任何事务,才正常执行。
NESTED 如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。
题目2:
链接:https://www.nowcoder.com/questionTerminal/c029bbab5f1645af85a318b455e8a4d4
来源:牛客网
A 拦截器是SpringMVC中的一个核心应用组件,主要用于处理多个 Controller的共性问题.当我们的请求由DispatcherServlet派发 到具体Controller之前首先要执行拦截器中一些相关方法,在这些 方法中可以对请求进行相应预处理(例如权限检测,参数验证),这些方法可以决定对这个请求进行拦截还是放行. >>服务器一启动,就会创建拦截器对象, >>对拦截器配置延迟加载是没有用的 >>拦截器是单例的,整个过程,拦截器只有一个实例对象 拦截器需要实现 HandleInterceptor接口,或者继承HandlerInterceptorAdaptor抽象类; HandlerInterceptor接口的三个方法: 1,preHandle() 是拦截器最先执行的方法,是在请求到达Controller之前执行的,其实就是拦截器用于拦截请求的,三个参数,分别是request,response,handelr就是这个请求要去找的后端处理器Controller.方法的返回值是bloolean类型,如果返回为false,就说明请求在此终结,不能执行后面的代码了.如果返回值为true,那么这个拦截器就要放行,将请求交给后端处理器Controller. 2,postHandle() 这个方法,是在后端控制器controller处理完请求之后,就执行的,这个方法,多了一个参数,ModelAndView,后端控制器controller处理请求可能需要返回页面和数据,所以会多一个ModelAndView,但是这个方法,是在渲染页面之前执行的,渲染热面是交个前端控制器来完成的. 3,afterCompletion() 拦截器最后执行的方法
题目3:
@Autowired是Spring提供的注解,@Resource是JDK提供的注解。
它们的区别是,@Autowired只能按类型注入(by-type),@Resource默认按名称注入(by-name),也支持by-type注入。
题目4:
Spring提供了众多容器类,最常用的有BeanFactory 和 ApplicationContext。
BeanFactory是ApplicationContext接口的父接口。
BeanFactory:是所有Spring Bean的容器根接口。是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。
ApplicationContext。以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,
题目5:
在Spring MVC中,Model、ModelMap(可以作为数据模型对象)、ModelAndView都可以作为数据模型对象,以上述类型作为控制器的方法参数时,Spring MVC会自动实例化这些类型。ModelAttribute是注解,用于定义控制器方法执行之前,对数据模型的操作。
BeanFactory是所有Spring Bean的容器根接口,其给IoC容器提供了一套完整的规范。FactoryBean是 一种创建Bean的方式,是对Bean的一种扩展。
题目6:
MVC的处理过程,
1)首先控制器C接受用户的请求,并决定应该调用哪个模型来进行处理,
2)然后模型M用业务逻辑来处理用户的请求并返回数据,
3)最后控制器用相应的视图V格式化模型返回的数据,并通过表示层呈现给用户。
题目7:
Spring IoC的注入方式有三种,分别是基于属性注入、基于构造方法注入、基于setter方法注入。
题目8:@RequestMapping,@RequestParam,与@ResponseBody
@RequestMapping的参数:
method属性代表指定请求的method的类型(定义处理 HTTP GET 请求的服务方法),
value属性指请求的实际地址(处理程序方法映射到的 URL),
params是指定request中一定要有的参数值。
required是@RequestParam注解的属性,是指该参数是否为必传项,默认为true,表示请求中一定要传入对应的参数。
@ResponseBody一般在异步获取数据时使用,但不代表它只能应用于异步请求之中。用于发送 Object 作为响应,通常用于发送 XML 或 JSON 数据作为响应。
题目9:SpringMVC 五大核心组件
1.DispatcherServlet 请求入口
2.HandlerMapping 请求派发,负责请求和控制器建立一一对应的关系
3.Controller 处理器
4.ModelAndView 封装模型信息和视图信息
5.ViewResolver 视图处理器,定位页面
SpringFactoriesLoader 该类并不对外暴露给应用开发者使用,而是Spring框架自己使用的内部工具类,本身被声明为抽象类(abstract),不可以被实例化。
题目10:管理Spring Bean的生命周期的注解是
@PostConstruct:在bean创建完成并且属性赋值完成后执行初始化方法。
@PreDestroy:在容器销毁bean之前通知我们进行清理工作。
题目11
IoC是控制反转的意思,这是一种面向对象的编程思想。
Spring采用依赖注入(DI)的方式,实现了IoC思想。
题目12
JDK动态代理,是Java提供的动态代理技术,可以在运行时创建接口的代理实例。
CGLib动态代理,采用底层的字节码技术,在运行时创建子类代理的实例。
题目13
@ComponentScan注解默认规则是对当前包及其子包中的Bean进行扫描。
题目14
Spring容器创建Bean对象的方法有三种方式,分别是:用构造器来实例化,使用静态工厂方法实例化和使用实例工厂方法实例化
题目15:Spring的事物传播行为
① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘
③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按
REQUIRED属性执行。
题目16
当发现有多种类型的Bean时,@Primary注解会通知IoC容器优先使用它所标注的Bean进行注入;@Quelifier注解可以与@AutoWired注解组合使用,达到通过类型和名称一起筛选Bean的效果。
java题目
题目1:垃圾回收
A: 垃圾回收在jvm中优先级相当相当低。
B:垃圾收集器(GC)程序开发者只能推荐JVM进行回收,但何时回收,回收哪些,程序员不能控制。
C:垃圾回收机制只是回收不再使用的JVM内存,如果程序有严重BUG,照样内存溢出。
D:进入DEAD的线程,它还可以恢复,GC不会回收
题目2:
public class Test{
static{
int x=5;
}
static int x,y;
public static void main(String args[]){
x–;
myMethod( );
System.out.println(x+y+ ++x);
}
public static void myMethod( ){
y=x++ + ++x;
}
}
解析:
1)因为静态块是局部变量,因此x不是5,而是未初始化,是0
2)x–,x变为-1
3)调用myMethod函数,x++,此时x++的值是-1,x的值是0,++x的值是1,因此此时,x的值是1,y的值是0
4)x+y+ ++x,x+y=1+0=1,++x的值是1+1=2,因此输出是3
题目3:
如果Child extends Parent,那么正确的有(BCD)?
如果Child是class,且只有一个有参数的构造函数,那么必然会调用Parent中相同参数的构造函数
如果Child是interface,那么Parent必然是interface
如果Child是interface,那么Child可以同时extends Parent1,Parent2等多个interface
如果Child是class,并且没有显示声明任何构造函数,那么此时仍然会调用Parent的构造函数
解析:
A 错误,可以调用父类无参的构造函数,没有必要必须调用相同的父类构造参数。子类的有参构造函数和是否调用父类的有参数的构造函数无必然联系。
B 接口继承的时候只能继承接口不能继承类,因为如果类可以存在非抽象的成员,如果接口继承了该类,那么接口必定从类中也继承了这些非抽象成员,这就和接口的定义相互矛盾,所以接口继承时只能继承接口。
C 接口可以多继承可以被多实现,因为接口中的方法都是抽象的,这些方法都被实现的类所实现,即使多个父接口中有同名的方法,在调用这些方法时调用的时子类的中被实现的方法,不存在歧义;同时,接口的中只有静态的常量,但是由于静态变量是在编译期决定调用关系的,即使存在一定的冲突也会在编译时提示出错;而引用静态变量一般直接使用类名或接口名,从而避免产生歧义,因此也不存在多继承的第一个缺点。 对于一个接口继承多个父接口的情况也一样不存在这些缺点。所以接口可以多继承。
D 子类即使没有显示构造函数,也会有个无参数的默认构造函数,仍然会调用父类的构造函数。
题目4:
public class Demo{
public static void main(String[] args){
System.out.print(getNumber(0));
System.out.print(getNumber(1));
System.out.print(getNumber(2));
System.out.print(getNumber(4));
}
public static int getNumber(int num){
try{
int result = 2 / num;
return result;
}catch (Exception exception){
return 0;
}finally{
if(num == 0){
return -1;
}
if(num == 1){
return 1;
}
}
}
}
解析:
finally一定在return之前执行。nums传入0,那么在finally里面return -1
传入1,那么在finally 中return 1
传入2,那么在try 里面return 2/2=1
传入4,那么在try 里面return 2/4=0 ,如果结果不是整数,那么取整
题目5:
class HasStatic{
private static int x = 100;
public static void main(String args[ ]){
HasStatic hs1 = new HasStatic();
hs1.x++;
HasStatic hs2 = new HasStatic();
hs2.x++;
hs1=new HasStatic();
hs1.x++;
HasStatic.x–;
System.out.println( “x=” +x);
}
}
解析:
因为x的 修饰符为 static 所以x为类变量,即对于所有的实例来说,他们访问的x为同一个x,类变量存储在方法区,不属于每个实例的私有,
刚开始x=100
调用hs1.x++ x为101;
调用hs2.x++ x为102;
调用hs1.x++ x为103 (此时hs1指向了一个新的HasStatic实例,但是依然访问的是同一个X)
调用HasStatic.x-- x为102
题目6:字符串拼接题目
System.out.println(“is ”+ 100 + 5);//字符串拼接,得到is 1005
System.out.println(100 + 5 +“ is”);//进行运算,得到105 is
System.out.println(“is ”+ (100 + 5));//先进行括号内的运算,再进行字符串拼接,得到is 105
解析:
前面出现字符串,后面的内容自动强制转换为string进行拼接
先出现数字,则进行加减运算
先算括号里面,数字
题目7:
String s = “hello”;
String t = “hello”;
char c[] = {‘h’, ‘e’, ‘l’, ‘l’, ‘o’} ;
s.equals(t);//true
t.equals©;//false
st;//true
t.equals(new String(“hello”));//true
解析
s和t两个String类型变量都是常量池中的字符串,只有变量名不同,s和t是地址相同,内容相同
String类型重写了equals方法,用于判断字符串内容是否相等,t和new出来的"hello"内容显然是相等的,D正确。
String底层源码的equals()方法处有判断这个参数是不是String类的实例,如果不是则不执行,判断直接返回false。B错误。
题目补充:
String s1 = “uml”;
String s2 = “uml”;
String s3= new String(“uml”);
String s4= new String(“uml”);
那么,s1s2(T);s3 == s4(F);s1.equals(s3)(T); 判断正确与否
s1s3(F),因为s3是在堆中创建的,地址和s1不一致
解析:
“”比较的是地址和值。 “equals”比较的是值。
s1==s2,比较的是比较的是地址和值,由上图得知两个引用指向的是同一个地址,所以返回true.
s3 == s4,比较的是两个new出来开辟的空间对象地址,所以值相同,但地址不同,返回false. s1.equals(s3),比较的是内容,返回true。
题目8:
public class Base
{
public void methodOne()
{
System.out.print(“A”);
methodTwo();
}
public void methodTwo()
{
System.out.print(“B”);
}
}
public class Derived extends Base
{
public void methodOne()
{
super.methodOne();
System.out.print(“C”);
}
public void methodTwo()
{
super.methodTwo();
System.out.print(“D”);
}
}
假定Base b = new Derived(); 调用执行b.methodOne()后,输出结果是什么?
知识点:
1.多态中成员方法使用规则 编译看左边,运行看右边。
2…多态中,子类重写的方法,当super调用就是调用父类方法。
因此输出结果就是,ABDC
题目9:list.add的参数说明
list.add(6);//在list后面添加数据
list.add(0,4);//在0号位置添加元素4
list.remove(1);//删除1号位置元素
题目10:
public class Test {
public static void main(String[] args) {
Father a = new Father();
Father b = new Child();
}
}
class Father {
public Father() {
System.out.println(“我是父类”);
}
}
class Child extends Father {
public Child() {
System.out.println(“我是子类”);
}
}
执行结果:
我是父类
我是父类
我是子类
解析:
父类new,执行父类构造方法。
子类new,先执行父类构造方法,再执行子类构造方法。
题目11:
public class Test {
private static int j = 0;
private static Boolean methodB(int k) {
j += k;
return true;
}
public static void methodA(int i) {
boolean b;
b = i < 10 | methodB(4);
b = i < 10 || methodB(8);
}
public static void main(String args[]) {
methodA(0);
System.out.println(j);
}
}
解析:输出结果是4
在main函数中先调用methodA(0) 在methodA中,第二行 b = i < 10 | methodB(4); //中间为与计算符,执行完methodB(4)后,j = 4
methodA中,第三行 b = i < 10 || methodB(8);//中间为或计算符,因为i < 10 已成立,不需要后续计算 所以最后结果输出为4。
题目12:
public class Test
{
public static Test t1 = new Test();
{
System.out.println(“blockA”);
}
static
{
System.out.println(“blockB”);
}
public static void main(String[] args)
{
Test t2 = new Test();
}
}
输出:blockAblockBblockA
解析:
静态块,非静态对象和非静态代码块,构造函数
public static Test t1 = new Test(); //(1)
static
{
System.out.println(“blockB”); //(2)
}
Test t2 =new Test(); //(3)
在执行(1)时创建了一个Test对象,在这个过程中会执行非静态代码块和缺省的无参构造函数,在执行非静态代码块时就输出了blockA;然后执行(2)输出blockB;执行(3)的过程同样会执行非静态代码块和缺省的无参构造函数,在执行非静态代码块时输出blockA。
另:
public class B
{
public static B t1 = new B();
public static B t2 = new B();
{
System.out.println(“构造块”);
}
static
{
System.out.println(“静态块”);
}
public static void main(String[] args)
{
B t = new B();
}
}
输出结果:构造块 构造块 静态块 构造块
解析:
静态块按照调用顺序执行。
public static B t1 = new B();(1)
public static B t2 = new B();(2)
Static
{
静态块 (3)
}
B t = new B(); (4)
在执行(1)时,执行非静态代码块和缺省的无参构造函数,在执行非静态代码块时就输出了 构造块,
在执行(2)时,执行非静态代码块和缺省的无参构造函数,在执行非静态代码块时就输出了构造块,
执行(3)时,输出静态块
执行(4)时,执行非静态代码块和缺省的无参构造函数,在执行非静态代码块时就输出了 构造块,
题目13:
String s=“welcome”+“to”+360;//一共创建了1次对象
String test=“javaandpython”;
String str1=“java”;
String str2=“and”;
String str3=“python”;
System. out. println(test==“java”+“and”+“python”): //一共创建了1次对象
System. out. println(test ==str1 + str2 + str3); //一共创建了3次对象
解析:
总结来说就是:字面量"+“拼接是在编译期间进行的,拼接后的字符串存放在字符串池中;而字符串引用的”+"拼接运算是在运行时进行的,新创建的字符串存放在堆中。
题目14:
public class MyThead extends Thread{
public static void main(String[] args) {
MyThead t=new MyThead();
MyThead s=new MyThead();
t.start();
System.out.println(“one.”);
s.start();
System.out.println(“two.”);
}
public void run() {
System.out.println(“Thread”);
}
}
解析:
多线程的执行顺序和run函数的顺序有关,和主函数的start调用顺序无关。
因此是随机执行
public class MyThead extends Thread{
public static void main(String[] args) {
MyThead t=new MyThead();
MyThead s=new MyThead();
t.run();
System.out.println(“one.”);
s.run();
System.out.println(“two.”);
}
public void run() {
System.out.println(“Thread”);
}
}
解析:
Thread.One.Thread.Two。顺序执行,相当于单线程