网站做多少屏合适,做药品网站有哪些,ajax瀑布流网站模板,电脑网站设计公司文章目录 Spring篇Spring核心推断构造方法AOP动态代理Advice的分类Advisor的理解AOP相关的概念 定义BeanASM技术JFR依赖注入循环依赖LifecycleSpring AOT Spring事务Spring事务传播机制Spring事务传播机制是如何实现的呢?Spring事务传播机制分类 SpringMVCHandlerHandlerMappi… 文章目录 Spring篇Spring核心推断构造方法AOP动态代理Advice的分类Advisor的理解AOP相关的概念 定义BeanASM技术JFR依赖注入循环依赖LifecycleSpring AOT Spring事务Spring事务传播机制Spring事务传播机制是如何实现的呢?Spring事务传播机制分类 SpringMVCHandlerHandlerMappingHandlerAdapterRequestMapping方法参数SPISpring MVC不常用注解InitBinderSessionAttributesRequestAttribute 与 SessionAttributeModelAttribute flashMap MyBatis篇MyBatis执行SQL流程分析MyBatis重要类分析MyBatis的二级缓存原理OGNL表达式Mybatis中的OGNL表达式Mybatis中的OGNL表达式拓展 Spring篇
Spring核心
推断构造方法
Spring会根据入参的类型和入参的名字去Spring中找Bean对象以单例Bean为例Spring会从单例池那个Map中去找
先根据入参类型找如果只找到一个那就直接用来作为入参如果根据类型找到多个则再根据入参名字来确定唯一一个会根据入参名字来找Map里面一样名字的作为入参。最终如果没有找到则会报错无法创建当前Bean对象
确定用哪个构造方法确定入参的Bean对象这个过程就叫做推断构造方法。
AOP
AOP全称是 Aspect Oriented Programming 即面向切面编程。是OOP的延续也是Spring框架中的一个重要内容是函数式编程的一种衍生泛型。简单的说他就是把我们程序重复的代码抽取出来在需要执行的时候使用动态代理技术在不修改源码的基础上对我们的已有方法进行增强。
动态代理
代理模式的解释为其他对象提供一种代理以控制对这个对象的访问增强一个类中的某个方法对程序进行扩展。
在Spring中进行了封装封装出来的类叫做ProxyFactory表示是创建代理对象的一个工厂使用起来会比JDK动态代理、cglib动态代理更加方便。
UserService target new UserService();ProxyFactory proxyFactory new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvice(new MethodInterceptor() {Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println(before...);Object result invocation.proceed();System.out.println(after...);return result;}
});UserInterface userService (UserInterface) proxyFactory.getProxy();
userService.test();通过ProxyFactory我们可以不再关心到底是用cglib还是jdk动态代理了ProxyFactory会帮我们去判断如果UserService实现了接口那么ProxyFactory底层就会用jdk动态代理如果没有实现接口就会用cglib技术上面的代码就是由于UserService实现了UserInterface接口所以最后产生的代理对象是UserInterface类型。
Advice的分类
Before Advice方法之前执行After returning advice方法return后执行After throwing advice方法抛异常后执行After (finally) advice方法执行完finally之后执行这是最后的比return更后Around advice这是功能最强大的Advice可以自定义执行顺序
Advisor的理解
跟Advice类似的还有一个Advisor的概念一个Advisor是有一个Pointcut和一个Advice组成的通过Pointcut可以指定要需要被代理的逻辑比如一个UserService类中有两个方法按上面的例子这两个方法都会被代理被增强那么我们现在可以通过Advisor来控制到具体代理哪一个方法比如 UserService target new UserService();ProxyFactory proxyFactory new ProxyFactory();proxyFactory.setTarget(target);proxyFactory.addAdvisor(new PointcutAdvisor() {Overridepublic Pointcut getPointcut() {return new StaticMethodMatcherPointcut() {Overridepublic boolean matches(Method method, Class? targetClass) {return method.getName().equals(testAbc);}};}Overridepublic Advice getAdvice() {return new MethodInterceptor() {Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println(before...);Object result invocation.proceed();System.out.println(after...);return result;}};}Overridepublic boolean isPerInstance() {return false;}});UserInterface userService (UserInterface) proxyFactory.getProxy();userService.test();上面代码表示产生的代理对象只有在执行testAbc这个方法时才会被增强会执行额外的逻辑而在执行其他方法时是不会增强的。
AOP相关的概念
Aspect表示切面比如被Aspect注解的类就是切面可以在切面中去定义Pointcut、Advice等等Join point表示连接点表示一个程序在执行过程中的一个点比如一个方法的执行比如一个异常的处理在Spring AOP中一个连接点通常表示一个方法的执行。Advice表示通知表示在一个特定连接点上所采取的动作。Advice分为不同的类型后面详细讨论在很多AOP框架中包括Spring会用Interceptor拦截器来实现Advice并且在连接点周围维护一个Interceptor链Pointcut表示切点用来匹配一个或多个连接点Advice与切点表达式是关联在一起的Advice将会执行在和切点表达式所匹配的连接点上Introduction可以使用DeclareParents来给所匹配的类添加一个接口并指定一个默认实现Target object目标对象被代理对象AOP proxy表示代理工厂用来创建代理对象的在Spring Framework中要么是JDK动态代理要么是CGLIB代理Weaving表示织入表示创建代理对象的动作这个动作可以发生在编译时期比如Aspejctj或者运行时比如Spring AOP
定义Bean
Spring中定义Bean的方式可以分为两类分别是声明式和编程式。顾名思义声明式可以理解为用一个的标记去标识相关的信息代码底层再对这些标识符进行一个解析处理编程式则更多侧重于使用代码的形式去处理相关逻辑。前者使用更友好后者更底层。
声明式标签、Bean注解、Component注解
编程式BeanDefinition接口、FactoryBean接口、Supplier接口
ASM技术
在Spring中需要去解析类的信息比如类名、类中的方法、类上的注解这些都可以称之为类的元数据所以Spring中对类的元数据做了抽象并提供了一些工具类。MetadataReader表示类的元数据读取器默认实现类为SimpleMetadataReader。需要注意的是SimpleMetadataReader去解析类时使用的ASM技术。
ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class 文件里这些类文件拥有足够的元数据来解析类中的所有元素类名称、方法、属性以及 Java 字节码指令。ASM 从类文件中读入信息后能够改变类行为分析类信息甚至能够根据用户要求生成新类。ASM并没有让这个类加载到JVM。
JFR
JFR资料介绍JFR 是 Java Flight Record Java飞行记录 的缩写是 JVM 内置的基于事件的JDK监控记录框架。这个起名就是参考了黑匣子对于飞机的作用将Java进程比喻成飞机飞行。顾名思义这个记录主要用于问题定位和持续监控。
依赖注入
依赖注入(Dependency Injection, DI)是一种设计模式也是Spring框架的核心概念之一。其作用是去除Java类之间的依赖关系实现松耦合以便于开发测试。依赖注入分为手动注入和自动注入两种注入方式。
手动注入在XML中定义Bean时就是手动注入因为是程序员手动给某个属性指定了值。手动注入分为两种 set方法注入 bean nameuserService classcom.luban.service.UserServiceproperty nameorderService reforderService/
/bean构造方法注入 bean nameuserService classcom.luban.service.UserServiceconstructor-arg index0 reforderService/
/bean自动注入分为两种 XML的autowire自动注入 在XML中我们可以在定义一个Bean时去指定这个Bean的自动注入模式 byTypebyNameconstructordefaultno bean iduserService classcom.luban.service.UserService autowirebyType/Autowired注解的自动注入 Autowired注解可以写在 属性上先根据属性类型去找Bean如果找到多个再根据属性名确定一个构造方法上先根据方法参数类型去找Bean如果找到多个再根据参数名确定一个set方法上先根据方法参数类型去找Bean如果找到多个再根据参数名确定一个
循环依赖
简单来说就是A对象依赖了B对象B对象依赖了A对象。
如果不考虑Spring循环依赖并不是问题因为对象之间相互依赖是很正常的事情。但是在Spring中循环依赖就是一个问题了因为在Spring中一个对象并不是简单new出来了而是会经过一系列的Bean的生命周期就是因为Bean的生命周期所以才会出现循环依赖问题。
Spring解决循环依赖使用了三级缓存。三级缓存是通用的叫法。 一级缓存为singletonObjects 二级缓存为earlySingletonObjects 三级缓存为**singletonFactories** singletonObjects中缓存的是已经经历了完整生命周期的bean对象。 earlySingletonObjects比singletonObjects多了一个early表示缓存的是早期的bean对象。早期是什么意思表示Bean的生命周期还没走完就把这个Bean放入了earlySingletonObjects。 singletonFactories中缓存的是ObjectFactory表示对象工厂表示用来创建早期bean对象的工厂。
Lifecycle
Lifecycle表示的是ApplicationContext的生命周期可以定义一个SmartLifecycle来监听ApplicationContext的启动和关闭
Component
public class isPaintingLifecycle implements SmartLifecycle {private boolean isRunning false;Overridepublic void start() {System.out.println(启动);isRunning true;}Overridepublic void stop() {// 要触发stop()要调用context.close()或者注册关闭钩子context.registerShutdownHook();System.out.println(停止);isRunning false;}Overridepublic boolean isRunning() {return isRunning;}
}Spring AOT
Spring 6 提供了一项新功能有望优化应用程序的性能 Ahead-of-TimeAOT 编译支持。
Ahead-of-TimeAOT提前编译或预编译是一种在应用程序运行前将字节码预编译为本地机器码的技术。
通过 AOT 编译构建的应用程序在性能和资源消耗方面具有多重优势
消除死代码AOT 编译器可以消除运行时从未执行过的代码。这样可以减少需要执行的代码量从而提高性能。内联内联是 AOT 编译器用函数的实际代码替换函数调用的一种技术。这可以减少函数调用的开销从而提高性能。常量传播AOT 编译器通过在编译时确定变量的常量值来替换变量从而优化性能。这样就无需进行运行时计算从而提高了性能。过程间优化AOT 编译器可通过分析程序的调用图来优化跨多个函数的代码。这可以通过减少函数调用的开销和识别常见的子表达式来提高性能。Bean 定义Spring 6 中的 AOT 编译器可减少不必要的 BeanDefinition 实例从而提高应用程序的效率。
因此让我们使用 AOT 优化命令来构建应用程序
mvn clean compile spring-boot:process-aot package然后使用命令运行应用程序
java -Dspring.aot.enabledtrue -jar jar-name我们可以设置构建插件默认启用 AOT 编译
plugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdexecutionsexecutionidprocess-aot/idgoalsgoalprocess-aot/goal/goals/execution/executions
/pluginSpring事务
Spring事务传播机制
Spring事务传播机制是如何实现的呢?
在执行某个方法时判断当前是否已经存在一个事务就是判断当前线程的ThreadLocal中是否存在一个数据库连接对象如果存在则表示已经存在一个事务了。
Spring事务传播机制分类
REQUIRED 默认传播行为支持当前事务如果当前没有事务就新建一个事务这个当前事务指的是上一个方法的事务是别人传递过去的类似于重入锁A方法和B方法都有事务A方法调用B方法A的事务会传递给B使它们共用同一个事务我起了个名字叫做重入事务 SUPPORTS 如果存在一个事务支持当前事务如果没有事务则非事务执行 REQUIRES_NEW 开启一个新的事务。如果一个事务已经存在则先将这个存在的事务挂起 MANDATORY 如果已经存在一个事务支持当前事务。如果没有一个活动的事务则抛出异常 NOT_SUPPORTED 总是非事务地执行并挂起任何存在的事务 NEVER 总是非事务地执行不加入任何事务 NESTED 如果一个活动的事务存在则运行在一个嵌套的事务中。 如果没有活动事务, 则按 REQUIRED 属性执行。
SpringMVC
Handler
Handler表示请求处理器在SpringMVC中有四种Handler 1、实现了Controller接口的Bean对象 2、实现了HttpRequestHandler接口的Bean对象 3、添加了RequestMapping注解的方法 4、一个HandlerFunction对象
HandlerMapping
HandlerMapping负责去寻找Handler并且保存路径和Handler之间的映射关系。
因为有不同类型的Handler所以在SpringMVC中会由不同的HandlerMapping来负责寻找Handler
HandlerAdapter
由于有不同种类的Handler所以执行方式是不一样的。所以按逻辑来说找到Handler之后我们得判断它的类型。把不同种类的Handler适配成一个HandlerAdapter后续再执行HandlerAdapter的handle()方法就能执行不同种类Hanlder对应的方法。
针对不同的Handler会有不同的适配器。
RequestMapping方法参数
当SpringMVC接收到请求并找到了对应的Method之后就要执行该方法了不过在执行之前需要根据方法定义的参数信息从请求中获取出对应的数据然后将数据传给方法并执行。
一个HttpServletRequest通常有
1、request parameter
2、request attribute
3、request session
4、reqeust header
5、reqeust body
比如如下几个方法
public String test(String username) {return ispainting;
}表示要从request parameter中获取key为username的value
public String test(RequestParam(uname) String username) {return ispainting;
}表示要从request parameter中获取key为uname的value
public String test(RequestAttribute String username) {return ispainting;
}表示要从request attribute中获取key为username的value
public String test(SessionAttribute String username) {return ispainting;
}表示要从request session中获取key为username的value
public String test(RequestHeader String username) {return ispainting;
}表示要从request header中获取key为username的value
public String test(RequestBody String username) {return ispainting;
}表示获取整个请求体
SPI
跟Tomcat的提供的扩展机制有关在SpringMVC中有这样一个类
HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {Overridepublic void onStartup(Nullable SetClass? webAppInitializerClasses, ServletContext servletContext)throws ServletException {// ...}}这个类实现了javax.servlet.ServletContainerInitializer接口并且在SpringMVC中还有这样一个文件META-INF/services/Tomcatjavax.servlet.ServletContainerInitializer文件内容为org.springframework.web.SpringServletContainerInitializer。
很明显是SPI所以Tomcat在启动过程中会找到这个SpringServletContainerInitializer并执行onStartup()
SPIService Provider Interface是JDK内置的一种服务提供发现机制可以用来启用框架扩展和替换组件。Java的SPI机制可以为某个接口寻找服务实现。Java中SPI机制主要思想是将装配的控制权移到程序之外在模块化设计中这个机制尤其重要其核心思想就是解耦。
SPI与API区别
API是调用并用于实现目标的类、接口、方法等的描述SPI是扩展和实现以实现目标的类、接口、方法等的描述
Spring MVC不常用注解
InitBinder
在参数绑定时进行可以针对复杂对象自定义参数绑定逻辑比如
GetMapping(/testInitBinder)
public String testInitBinder(Date date){return date.toString();
}此时如果访问http://localhost:8080/tuling-web/app/testInitBinder?date1111-1-1会报错。
此时可以在当前Controller中添加
InitBinder
public void initBinder(WebDataBinder binder) {SimpleDateFormat dateFormat new SimpleDateFormat(yyyy-MM-dd);dateFormat.setLenient(false);binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}有了这个就相当于添加了一个自定义的日期格式转换器这样就能正常访问了。
注意如果我们想把String类型转成我们自定义的User类那么在User类中得提供一个String类型的构造方法
SessionAttributes
只能写在类上通过SessionAttributes注解指定model中哪些key的value存到session中。
RequestAttribute 与 SessionAttribute
都只能写在方法参数前面表示从相对应request.getAttribute()、session.getAttribute()中获取值传递给方法参数
ModelAttribute
可以写在某个方法上ModelAttribute可以定义在一个Controller中当请求这个Controller中的方法时会先调用ModelAttribute所修饰的方法方法返回的值会添加到model中比如以下代码就会向model中添加一个key为uservalues为请求中user参数所传递的值。
flashMap
在重定向时FlashMap机制提供了这么一种方式让一个请求传递一些参数给接下来的某个请求FlashMap机制保证了参数的隐蔽性不需要将参数传递到前端。
我们可以通过FlashMap来进行传递
Controller
public class IsPaintingController {GetMapping(/a)public String test(HttpServletRequest request, Model model) {FlashMap outputFlashMap RequestContextUtils.getOutputFlashMap(request);outputFlashMap.put(username, ispainting);return redirect:/b;}GetMapping(/b)ResponseBodypublic String a(HttpServletRequest request, Model model) {MapString, ? inputFlashMap RequestContextUtils.getInputFlashMap(request);String username (String) inputFlashMap.get(username);return username;}
}把要传递的参数存入outputFlashMap在b请求里通过inputFlashMap就可以拿到了底层是基于session来实现的。
MyBatis篇
ORM是Object-Relational Mapping的缩写中文通常翻译为对象关系映射。
传统JDBC规范掌握四个核心对象
DriverManager:用于注册驱动 Connection: 表示与数据库创建的连接 Statement: 操作数据库sql语句的对象 ResultSet: 结果集或一张虚拟表
MyBatis执行SQL流程分析
Executor分成两大类一类是CacheExecutor另一类是普通Executor。
CacheExecutor其实是封装了普通的Executor和普通的区别是在查询前先会查询缓存中是否存在结果如果存在就使用缓存中的结果如果不存在还是使用普通的Executor进行查询再将查询出来的结果存入缓存。
普通Executor又分为三种基本的Executor执行器SimpleExecutor、ReuseExecutor、BatchExecutor。
SimpleExecutor每执行一次update或select就开启一个Statement对象用完立刻关闭Statement对象。ReuseExecutor执行update或select以sql作为key查找Statement对象存在就使用不存在就创建用完后不关闭Statement对象而是放置于Map内供下一次使用。简言之就是重复使用Statement对象。BatchExecutor执行update没有selectJDBC批处理不支持select将所有sql都添加到批处理中addBatch()等待统一执行executeBatch()它缓存了多个Statement对象每个Statement对象都是addBatch()完毕后等待逐一执行executeBatch()批处理。与JDBC批处理相同。
作用范围Executor的这些特点都严格限制在SqlSession生命周期范围内。
MyBatis重要类分析
重要类
MapperRegistry本质上是一个Map其中的key是Mapper接口的全限定名value的MapperProxyFactoryMapperProxyFactory这个类是MapperRegistry中存的value值在通过sqlSession获取Mapper时其实先获取到的是这个工厂然后通过这个工厂创建Mapper的动态代理类MapperProxy实现了InvocationHandler接口Mapper的动态代理接口方法的调用都会到达这个类的invoke方法MapperMethod判断你当前执行的方式是增删改查哪一种并通过SqlSession执行相应的操作SqlSession作为MyBatis工作的主要顶层API表示和数据库交互的会话完成必要数据库增删改查功能ExecutorMyBatis执行器是MyBatis 调度的核心负责SQL语句的生成和查询缓存的维护
StatementHandler:封装了JDBC Statement操作负责对JDBC statement 的操作如设置参数、将Statement结果集转换成List集合。
ParameterHandler:负责对用户传递的参数转换成JDBC Statement 所需要的参数
ResultSetHandler:负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
TypeHandler:负责java数据类型和jdbc数据类型之间的映射和转换
MappedStatement:MappedStatement维护了一条节点的封装
SqlSource:负责根据用户传递的parameterObject动态地生成SQL语句将信息封装到BoundSql对象中并返回
BoundSql:表示动态生成的SQL语句以及相应的参数信息
Configuration:MyBatis所有的配置信息都维持在Configuration对象之中。
MyBatis的二级缓存原理
mybatis使用的是溢出淘汰机制。二级缓存在结构设计上采用装饰器责任链模式
mybatis缓存分为一级缓存和二级缓存
一级缓存又叫本地缓存是PerpetualCache类型的永久缓存保存在执行器中BaseExecutor而执行器又在SqlSessionDefaultSqlSession中所以一级缓存的生命周期与SqlSession是相同的。二级缓存又叫自定义缓存实现了Cache接口的类都可以作为二级缓存所以可配置如encache等的第三方缓存。二级缓存以namespace名称空间为其唯一标识被保存在Configuration核心配置对象中。
二级缓存对象的默认类型为PerpetualCache如果配置的缓存是默认类型则mybatis会根据配置自动追加一系列装饰器。
OGNL表达式
OGNL是一种表达式语言专门用于处理对象图中的数据。
OGNL表达式的语法非常简洁明了类似于XPath表达式。它使用点符号.来访问对象的属性使用方括号[]来访问集合和数组元素。以下是一些常见的OGNL语法示例 访问属性假设有一个名为person的对象其中包含属性name和age我们可以使用如下OGNL表达式来获取属性值 person.nameperson.age调用方法假设有一个名为order的对象其中包含方法getTotal()我们可以使用如下OGNL表达式来调用该方法 order.getTotal()访问集合和数组假设有一个名为items的List对象我们可以使用如下OGNL表达式来访问其中的元素 items[0]items[1]Mybatis中的OGNL表达式
在Mybatis中可以在SQL映射文件中使用${和}符号来嵌入OGNL表达式如
select idfindPersonById resultTypePersonSELECT * FROM person WHERE id #{id} AND city #{address.city}
/select其中#{id}和#{address.city}是OGNL表达式用于访问Person对象的id属性和Address对象的city属性。
Mybatis中的OGNL表达式拓展
在Mybatis中可以使用Hutool的OGNL工具类来实现OGNL表达式的拓展。
select idfindPersons resultTypePersonSELECT * FROM personif testcn.hutool.core.util.StrUtilisNotBlank(name)AND name LIKE CONCAT(%, #{name}, %)/ifif testage ! nullAND age #{age}/ifif testcn.hutool.core.util.StrUtilisNotBlank(city)AND city #{city.substring(0, 2)}/if
/select其中cn.hutool.core.util.StrUtilisNotBlank(name)和cn.hutool.core.util.StrUtilisNotBlank(city)是OGNL表达式用于调用StrUtil工具类的isNotBlank方法并将name和city属性作为参数传递。CONCAT(‘%’, #{name}, ‘%’)是SQL函数用于实现字符串的拼接。#{city.substring(0, 2)}是OGNL表达式用于实现字符串的截取。
需要注意的是在使用Hutool的OGNL工具类时需要在Mybatis的配置文件中进行相应的配置如
configurationsettingssetting nameognl.classResolver valuecn.hutool.ognl.HutoolClassResolver//settings
/configuration其中ognl.classResolver是Mybatis的配置项用于指定OGNL表达式的类加载器。cn.hutool.ognl.HutoolClassResolver是Hutool的OGNL类加载器用于实现OGNL表达式的拓展。