Spring基础知识整理
1. spring 组件
Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 Expression Language 表达式语言模块组成,具体介绍如下。
Beans 模块:提供了 BeanFactory,是工厂模式的经典实现,Spring 将管理对象称为 Bean。
Core 核心模块:提供了 Spring 框架的基本组成部分,包括 IoC 和 DI 功能。
Context 上下文模块:建立在核心和 Beans 模块的基础之上,它是访问定义和配置任何对象的媒介。ApplicationContext 接口是上下文模块的焦点。
Expression Language 模块:是运行时查询和操作对象图的强大的表达式语言。
2. spring
2.1 IOC
概述
一句话:创建对象交给容器
通过容器去获取对象
2.2 IOC底层原理
1 XML解析技术读取配置文件
<bean id="empDao" class="com.msb.dao.impl.EmpDaoImpl"></bean>
2 反射技术实例化对象,放到容器中
获得类的字节码 Class clazz =Class.forName("com.msb.dao.impl.EmpDaoImpl") 通过字节码实例化对象 Object obj = clazz.newInstance(); 将对象放到一个map集合中 map.put("empDao",obj)
3工厂模式返回Bean对象 getBean方法
IOC接口 BeanFactory 接口: IOC容器基本功能接口,是spring内部使用的接口,我们在处理业务时一般不直接使用该接口 ApplicationContext 接口: BeanFactory的子接口,提供更多更强大的功能,研发人员一般使用的接口
2.3 注解方式创建对象IOC
第一步:在applicationContext.xml中配置开启注解扫描
第二步:在类上添加注解,让spring容器给我们创建bean实例并存储于容器中
组件扫描配置注解识别
3. AOP
3.1 jdk 的动态代理
package cn.hba.modules.bootstrap.mq; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; /** * @Author: Ma HaiYang * @Description: MircoMessage:Mark_7001 */ public class Test1 { public static void main(String[] args) { Dinner dinner=new Person("张三"); // 通过Porxy动态代理获得一个代理对象,在代理对象中,对某个方法进行增强 // ClassLoader loader,被代理的对象的类加载器 ClassLoader classLoader = dinner.getClass().getClassLoader(); // Class<?>[] interfaces,被代理对象所实现的所有接口 Class[] interaces= dinner.getClass().getInterfaces(); // InvocationHandler h,执行处理器对象,专门用于定义增强的规则 InvocationHandler handler = new InvocationHandler(){ // invoke 当我们让代理对象调用任何方法时,都会触发invoke方法的执行 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // Object proxy, 代理对象 // Method method,被代理的方法 // Object[] args,被代理方法运行时的实参 Object res=null; if(method.getName().equals("eat")){ System.out.println("饭前洗手"); // 让原有的eat的方法去运行 res =method.invoke(dinner, args); System.out.println("饭后刷碗"); }else{ // 如果是其他方法,那么正常执行就可以了 res =method.invoke(dinner, args); } return res; } }; Dinner dinnerProxy =(Dinner) Proxy.newProxyInstance(classLoader,interaces,handler); dinnerProxy.eat("包子"); //dinnerProxy.drink(); } } interface Dinner{ void eat(String foodName); void drink(); } class Person implements Dinner{ private String name; public Person(String name) { this.name = name; } @Override public void eat(String foodName) { System.out.println(name+"正在吃"+foodName); } @Override public void drink( ) { System.out.println(name+"正在喝茶"); } } class Student implements Dinner{ private String name; public Student(String name) { this.name = name; } @Override public void eat(String foodName) { System.out.println(name+"正在食堂吃"+foodName); } @Override public void drink( ) { System.out.println(name+"正在喝可乐"); } }
3.2 cjlib的动态代理
import org.junit.Test; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @Author: Ma HaiYang * @Description: MircoMessage:Mark_7001 */ public class Test1 { @Test public void testCglib(){ Person person =new Person(); // 获取一个Person的代理对象 // 1 获得一个Enhancer对象 Enhancer enhancer=new Enhancer(); // 2 设置父类字节码 enhancer.setSuperclass(person.getClass()); // 3 获取MethodIntercepter对象 用于定义增强规则 MethodInterceptor methodInterceptor=new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { /*Object o, 生成之后的代理对象 personProxy Method method, 父类中原本要执行的方法 Person>>> eat() Object[] objects, 方法在调用时传入的实参数组 MethodProxy methodProxy 子类中重写父类的方法 personProxy >>> eat() */ Object res =null; if(method.getName().equals("eat")){ // 如果是eat方法 则增强并运行 System.out.println("饭前洗手"); res=methodProxy.invokeSuper(o,objects); System.out.println("饭后刷碗"); }else{ // 如果是其他方法 不增强运行 res=methodProxy.invokeSuper(o,objects); // 子类对象方法在执行,默认会调用父类对应被重写的方法 } return res; } }; // 4 设置methodInterceptor enhancer.setCallback(methodInterceptor); // 5 获得代理对象 Person personProxy = (Person)enhancer.create(); // 6 使用代理对象完成功能 personProxy.eat("包子"); } } class Person { public Person( ) { } public void eat(String foodName) { System.out.println("张三正在吃"+foodName); } }
3.3 总结
1. 使用静态代理,每一个代理,都要写一个代理对象 2. 静态代理,就是在原有的类外面在套一个代理类,增强原有的类的功能 3. 一般可以帮助我们在不修改现有代码的情况下,对程序的功能进行拓展,往往用于实现 日志处理,权限控制,性能检测,事务控制等 4. AOP实现的原理就是动态代理,在有接口的情况下,使用JDK动态代理,在没有接口的情况下使用cglib动态代理
3. 4 spring 中使用AOP
-
定义切点
-
配置类
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @ComponentScan(basePackages = "com.msb") @EnableAspectJAutoProxy(proxyTargetClass = true) public class SpringConfig { } -
写切面类
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.util.Arrays; /** * @Author: Ma HaiYang * @Description: MircoMessage:Mark_7001 */ @Component @Aspect public class DaoAspect { //定义公共切点 @Pointcut("execution(* com.msb.dao.*.add*(..))") public void addPointCut(){} /* * 前置通知: 切点方法执行之前先执行的功能 * 参数列表可以用JoinPoint接收切点对象 * 可以获取方法执行的参数 * */ @Before("addPointCut()") public void methodBefore(JoinPoint joinPoint){ System.out.println("Before invoked"); } /* * 后置通知:方法执行之后要增强的功能 * 无论切点方法是否出现异常都会执行的方法 * 参数列表可以用JoinPoint接收切点对象 * */ @After("addPointCut()") public void methodAfter(JoinPoint joinPoint){ System.out.println("After invoked"); } /* * 返回通知:切点方法正常运行结束后增强的功能 * 如果方法运行过程中出现异常,则该功能不运行 * 参数列表可以用 JoinPoint joinPoint接收切点对象 * 可以用Object res接收方法返回值,需要用returning指定返回值名称 * */ @AfterReturning( value = "addPointCut()",returning = "res") public void methodAfterReturning(JoinPoint joinPoint,Object res){ System.out.println("AfterReturning invoked"); } /* * 异常通知:切点方法出现异常时运行的增强功能 * 如果方法运行没有出现异常,则该功能不运行 * 参数列表可以用Exception ex接收异常对象 需要通过throwing指定异常名称 * */ @AfterThrowing( value = "addPointCut()",throwing = "ex") public void methodAfterThrowing(Exception ex){ System.out.println("AfterThrowing invoked"); } /*环绕通知:在切点方法之前和之后都进行功能的增强 * 需要在通知中定义方法执行的位置,并在执行位置之前和之后自定义增强的功能 * 方法列表可以通过ProceedingJoinPoint获取执行的切点 * 通过proceedingJoinPoint.proceed()方法控制切点方法的执行位置 * proceedingJoinPoint.proceed()方法会将切点方法的返回值获取到,并交给我们,可以做后续处理 * 我们在环绕通知的最后需要将切点方法的返回值继续向上返回,否则切点方法在执行时接收不到返回值 * */ @Around("addPointCut()") public Object methodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("aroundA invoked"); Object proceed = proceedingJoinPoint.proceed(); System.out.println("aroundB invoked"); return proceed; } }
4. bean的生命周期
1 通过构造器创建bean实例 执行构造器
2 为bean属性赋值 执行set方法
3 初始化bean 调用bean的初始化方法,需要配置指定调用的方法
4 bean的获取 容器对象 getBean方法
5 容器关闭销毁bean 调用销毁方法,需要配置指定调用的方法
5. bean自动装配
一个类里面包含其他类的对象,实用@autowire 或者@Resouce
* @Autowired * 根据类型到容器中去寻找对应的对象,找到后给当前属性赋值 * 不需要依赖 set方法 * 属性类型可以是接口,会自动匹配对应的实现类对象 * @Autowired配合 @Qualifier,可以通过名称指定注入的对象 * * @Resource 如果不配置name 那么就是根据类型注入 * @Resource(name="userDaoImplB") 配置name,就是根据名称注入 * * * @Resource 是JDK中javax包的注解 * @Autowired 和 @Qualifier 是spring中的注解 * * @Value 可以个普通属性赋值 * @Value 可以使用${}这种表达式获取系统的变量值 * 或者是.properties属性配置文件中的值 *
6. 使用外部文件
这个是spring 的获取外部文件,springboot 使用约定的方式无需指定配置文件的位置
3. SpringMVC
常用注解
1、@RequestMapping
2. @RequestParam
3、@PathVariable
4、@RequestHeader(了解)
5、@CookieValue(了解)
1、@RequestMapping 作用: 用于建立请求 URL 和处理请求方法之间的对应关系 出现位置: 类上: 请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头 方法上: 请求 URL 的第二级访问目录 属性: value:用于指定请求的 URL。它和 path 属性的作用是一样的。 method:用于指定请求的方式。 params(了解):用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的一模一样。 headers(了解):用于指定限制请求消息头的条件。 2 @RequestParam 作用: 把请求中指定名称的参数给控制器中的形参赋值。 属性: value:请求参数中的名称。 required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。 @RequestMapping("/getRequestParam") public String getRequestParam(@RequestParam("name")String uname, @RequestParam(value="age",required=false)Integer age){ System.out.println(username+","+age); return "success"; } 3、@PathVariable Restful的简介 : REST(英文:Representational State Transfer,简称 REST)restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。 restful 的优点 它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。 作用: 用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。 url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。 属性: value:用于指定 url 中占位符名称。 required:是否必须提供占位符。 @Controller public class PathController { @RequestMapping("/testPathVariable/{id}/{username}") public String testPathVariable(@PathVariable("id") Integer id, @PathVariable("username") String username){ System.out.println("id:"+id); System.out.println("username:"+username); System.out.println("testPathVariable1"); return "success"; } } 4、@RequestHeader(了解) 作用: 用于获取请求消息头。 属性: value:提供消息头名称 required:是否必须有此消息头 @RequestMapping("/getRequestHeader") public String getRequestHeader(@RequestHeader(value="Accept", required=false)String requestHeader){ System.out.println(requestHeader); return "success"; } 5、@CookieValue(了解) 作用: 用于把指定 cookie 名称的值传入控制器方法参数。 属性: value:指定 cookie 的名称。 required:是否必须有此 cookie 实现 @RequestMapping("/getCookie") public String getCookie(@CookieValue(value="JSESSIONID",required=false) String cookieValue){ System.out.println(cookieValue); return "success"; }
4.0 SpringBoot
PageHelp实现原理
PageHelper方法使用了静态的ThreadLocal参数,分页参数和线程是绑定的。内部流程是ThreadLocal中设置了分页参数(pageIndex,pageSize),之后在查询执行的时候,获取当线程中的分页参数,执行查询的时候通过拦截器在sql语句中添加分页参数,之后实现分页查询,查询结束后在 finally 语句中清除ThreadLocal中的查询参数
PageHelp使用方法
1.调用PageHelper方法:PageHelper.startPage(pageNum, pageSize) 2. MyBatis 查询方法 注意:只要你可以保证在PageHelper方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为PageHelper在finally代码段中自动清除了ThreadLocal存储的对象。
拦截器和过滤器的区别
1拦截器SpringMVC的,而过滤器是servlet的。 2拦截器不依赖与servlet容器,由spring容器初始化,过滤器依赖与servlet容器,由servlet容器初始化。 3拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。 4拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。 5在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。 6拦截器可以获取IOC容器中的各个bean,而过滤器就不太方便,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
1. 新建拦截器类。
新建拦截器类。
注意:不要忘记类上注解@Component
@Component public class DemoInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("执行拦截器"); return true; } }
2. 配置拦截器
注意:类上有注解@Configuration。此类相当于SpringMVC配置文件。
addPathPattern(): 拦截哪些URL。 / 拦截全部
excludePathPatterns(): 不拦截哪些URL。当和addPathPattern()冲突时,excludePathPatterns()生效。
@Configuration public class MyConfig implements WebMvcConfigurer { @Autowired private DemoInterceptor demoInterceptor; //配置拦截器的映射 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(demoInterceptor).addPathPatterns("/**").excludePathPatterns("/login"); } }
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
· 全程使用 AI 从 0 到 1 写了个小工具