Spring学习(六)
AOP和OOP
1、OOP:Object-Oriented Programming,面向对象程序设计,是静态的,一旦类写死了就不能改变了,要更改就得修改代码重新编译,父类类型引用指向对象来实现动态性。核心思想是将客观存在的不同事物抽象成相互独立的类,然后把与事物相关的属性和行为封装到类里,并通过继承和多态来定义类彼此间的关系,最后通过操作类的实例来完成实际业务逻辑的功能需求。
2、AOP:Aspect-Oriented Programming,面向切面编程,以OOP为基础修复本身不具备的能力具有动态语言的特点,和OOP互为补充,Aop的最大意义是在不改变原来代码的前提下,也不对源代码做任何协议接口要求, 对OOP而实现了类似插件的方式,来修改源代码,给源代码插入新的执行代码。核心思想是将业务逻辑中与类不相关的通用功能切面式的提取分离出来,让多个类共享一个行为,一旦这个行为发生改变,不必修改类,而只需要修改这个行为即可。Spring的AOP其代码实质,即代理模式的应用。
3、OOP和AOP的区别
- 面向目标不同:简单来说OOP是面向名词领域,AOP面向动词领域。
- 思想结构不同:OOP是纵向结构,AOP是横向结构。
- 注重方面不同:OOP注重业务逻辑单元的划分,AOP偏重业务处理过程的某个步骤或阶段。
4、OOP和AOP的联系:两者之间是一个相互补充和完善的关系
5、AOP优点:利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
6、AOP应用
日志记录、事务处理、异常处理、安全控制和性能统计方面。
在Spring中提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务和事务进行内聚性的开发。
AOP的重要概念
1、切面 : 切点(Pointcut) + Advice【 在哪里 、加什么 】
2、Advice: 在 切点 选中的 连接点 "加入" 的 代码 就是 Advice【确定 加什么 】
3、切点( Pointcut ) : 用来 筛选 连接点 的条件就是切点, 类似于sql语句,where条件就可以理解为切点【 确定 在哪里加 ,在那些方法里面加入代码】
4、连接点( Join Point ) : 执行点 + 方位信息 所有被拦截的方法被加入了其他的方法,通过代理的方法将想要加入的想要的代码,加入的代码和原有的代码形成了连接点。一个方法有5个连接点,四个方法就有20个
- 一个正在执行的方法 (执行点) 执行前 (方位信息)
- 一个正在执行的方法 (执行点) 执行前、后 (方位信息)
- 一个正在执行的方法 (执行点) 执行并返回后 (方位信息)
- 一个正在执行的方法 (执行点) 执行抛出异常后 (方位信息)
- 一个正在执行的方法 (执行点) 执行后 (方位信息)
5、方位信息
- 方法执行前 ( before ) 、
- 执行前和执行后,执行前后都有环绕,两个结合起来才可以使用,两者之间是有联系的 ( around ) 、
- 正常执行并返回后 ( after-returning ) 、
- 方法抛出异常后 ( after-throwing ) 、
- 方法执行后 ( after )
6、执行点:一个可以执行的方法在执行时就是一个执行点
7、代理目标: 哪个对象将被其它对象所代理 ( 谁将被别人代理 ) [ target ]
8、代理对象: 哪个对象将要去代理别的对象 ( 谁将去代理别人 ) [ proxy ]
代理模式
1、什么是代理呢?
例如:苹果公司的手机交由富士康工厂按照苹果公司的要求去生产手机,富士康工厂生产的手机由京东按照苹果公司的要求去完成销售,京东就可以看成是富士康的代理商(代理对象),而富士康就是代理目标。消费者在京东买手机,感觉是由京东提供的手机,实际上是由富士康生产的,由京东代理,这种思想就是代理思想
2、具体代码实例
IPhone 苹果手机类
package ecut.aop.proxy; public class IPhone { public IPhone(){
super();
System.out.println( "爱疯" );
} public void charge() {
System.out.println( "charge" );
} public void call() {
System.out.println( "call" );
} public void message() {
System.out.println( "message" );
} }
AppleCompany 苹果公司接口
package ecut.aop.proxy; public interface AppleCompany {
//由苹果公司去设计然后交由富士康生产
public IPhone create() ; }
FoxconnFactory 富士康工厂类
package ecut.aop.proxy; public class FoxconnFactory implements AppleCompany {
//需要实现苹果公司接口
@Override
public IPhone create() {
System.out.println( "富士康" );
IPhone phone = new IPhone();
return phone ;
} @Override
public String toString() {
return "FoxconnFactory";
} }
JingDong 京东类
package ecut.aop.proxy; public class JingDong implements AppleCompany { private FoxconnFactory factory ; @Override
public IPhone create() {
System.out.println( "京东" );
return factory.create() ;
}
//通过getter , setter 方法注入FoxconnFactory
public FoxconnFactory getFactory() {
return factory;
} public void setFactory(FoxconnFactory factory) {
this.factory = factory;
} }
Main主类
package ecut.aop.proxy; public class Main { public static void main(String[] args) {
//被代理的目标target, 京东买的手机由富士康生产
FoxconnFactory factory = new FoxconnFactory();
//京东是富士康的代理商,代理对象proxy,代理商和代理对象都实现了苹果公司的这个接口(前提),富士康按照苹果公司要求生产,京东按照苹果公司的要求买手机
JingDong jd = new JingDong(); jd.setFactory(factory);
//相当于消费者买手机
IPhone p = jd.create(); System.out.println( p ); p.call(); } }
先调用JingDong的create方法,实际上调用的FoxconnFactory的create方法(调用的proxy方法的时候调用target方法,表面上感觉是proxy调用的实际上target完成具体实现的)。用JingDong之所以可以代理FoxconnFactory,是因为FoxconnFactory和JingDong都实现了AppleCompany,这个是代理的前提
3、代理模式代码的主要特点是:不改变原有类的前提下,在原有类某些方法执行前后,插入任意代码。所以代理模式需要写新的类对原有的类进行包装。Struts2中的拦截器,Spring中的赖加载都是用代理模式实现
4、代理模式目前实现的方式有三种:
- 静态代理:需要增强原有类的哪个方法,就需要对在代理类中包装哪个方法。个人理解,从功能上来说,原有类和代理类不一定要实现共同接口,但是为了赋予代理和和被代理类之间的逻辑关系,增加程序的可读性,可理解性,逻辑性,增加代理对象和被代理对象之间的关系,以更加符合面向对象编程是思维,而应该实现共同接口。
- 动态代理:使用反射机制,方法和对象都是传入的变量,就可以经过传入的对象和方法而动态调用被代理对象的任何方法,jdk中提供了实现此动态代理的api,被代理类必须实现接口
- Cglib代理:返回对象是代理对象的子类,不需要代理对象实现接口。当调用原对象方法时,实际上调用的是代理子类的方法。
JDK动态代理
1、目的:通过反射实现动态产生一个代理对象来代理富士康工厂(代理目标)
2、动态代理主要是通过Proxy类中的newProxyInstance创建一个代理对象,newProxyInstance方法需要传三个参数ClassLoader loader,Class<?>[] interfaces,InvocationHandler h。
- ClassLoader loader:代理目标对应的 类的 "类加载器"
- Class<?>[] interfaces:代理目标对应的类所直接实现的接口
- InvocationHandler h:请求指派器,将代理对象的请求派遣个代理目标
3、InvocationHandler 请求指派器的作用就是作用就是要将代理对象的请求派遣个代理目标(调用的proxy方法的时候调用target方法,表面上感觉是proxy调用的实际上target完成具体实现的)。首先要通过匿名内部类实现InvocationHandler接口,并实现接口中的方法invoke( Object proxy , Method method , Object[] args )
- Object proxy:代理对象
- Method method:调用的方法
- Object[] args:方法中要传入的参数
在invoke方法中要是proxy和target产生联系通过method.invoke( target , args ) 来实现将代理对象的请求派遣个代理目标
4、测试代码如下
package ecut.aop.proxy; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays; public class ProxyTest { public static void main(String[] args) { // 代理目标 ( 谁将被别人代理 )
final Object target = new FoxconnFactory(); // 代理目标 的类型 : 获得 被代理的 对象的 运行时 类型,jdk代理的缺陷(前提)代理的目标类得实现接口,Spring提供了子类代理父类(Cglib)
Class<?> targetClass = target.getClass(); /** 用 代理目标 类型对应的类加载器 去加载 运行阶段动态产生的 代理类 */
ClassLoader loader = targetClass.getClassLoader() ; // 获得 代理目标 对应的 类的 "类加载器" /** 指示 将来产生 动态代理类 所需要实现的接口 */
Class<?>[] interfaces = targetClass.getInterfaces() ; // 获得 代理目标 对应的类所直接实现的接口
System.out.println( Arrays.toString( interfaces ) ); /** 请求指派器 (快递公司),调用的proxy方法的时候调用target方法,给你感觉是proxy调用的实际上target实现的,是使proxy 和 target产生联系,InvocationHandler将请求派给target
* method被调用的方法是谁, args 方法中的参数"借尸还魂"匿名内部类 */
InvocationHandler handler = new InvocationHandler(){
@Override
//proxy对象
public Object invoke( Object proxy , Method method , Object[] args ) throws Throwable {
//target.method(args);//被调用的是method方法;传入的参数是args;调用的是target所引用的对象的method方法
Object result = method.invoke( target , args ) ; // target.create();指派给target,由target调用方法 return result;
}
} ;
// 代理对象 ( 谁将去代理别人 )Proxy动态代理类的父类Proxy.newProxyInstance创建一个代理对象
Object proxy = Proxy.newProxyInstance( loader , interfaces , handler ) ; System.out.println( proxy ); // proxy.toString()会被指派,通过InvocationHandler.invoke方法指派给target.toString(),因此返回的是target的tostring方法 // proxy.getClass()不会被指派。代理类 : ( 在 运行阶段 动态产生 ( 没有 .java 文件、没有 .class 文件 ,直接产生字节码放在内存中去) )
Class<?> proxyClass = proxy.getClass(); System.out.println( proxyClass ); // 所有的 由 java.lang.refrect.Proxy 产生的 动态代理类 的直接父类都是 Proxy
System.out.println( proxyClass.getSuperclass() ); // 获得 动态代理类 所实现过的 接口 ( 在 创建 代理对象时指定的数组中有哪些接口,这里就有哪些接口 )
System.out.println( Arrays.toString( proxyClass.getInterfaces() ) ); System.out.println( "~~~构造方法~~~~~~~~~~~~" ); Constructor<?>[] cons = proxyClass.getDeclaredConstructors();
for( Constructor<?> c : cons ){
System.out.println( c );
} System.out.println( "~~~ 属性 ( Field ) ~~~~~~~~~~~~" );
//属性都由private static修饰 ,代理对象 $Proxy0继承了父类的Proxy类中的protected InvocationHandler h属性,其他m0,m1....都与方法相对应
Field[] fields = proxyClass.getDeclaredFields();
for( Field c : fields ){
System.out.println( c );
} System.out.println( "~~~ 方法 ( Method ) ~~~~~~~~~~~~" );
//重写了toString,hashCode,equals方法,都由public final修饰
Method[] methods = proxyClass.getDeclaredMethods();
for( Method c : methods ){
System.out.println( c );
} } }
运行结果如下:
[interface ecut.aop.proxy.AppleCompany]
FoxconnFactory
class com.sun.proxy.$Proxy0
class java.lang.reflect.Proxy
[interface ecut.aop.proxy.AppleCompany]
~~~构造方法~~~~~~~~~~~~
public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
~~~ 属性 ( Field ) ~~~~~~~~~~~~
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m1
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m2
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m3
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m0
~~~ 方法 ( Method ) ~~~~~~~~~~~~
public final boolean com.sun.proxy.$Proxy0.equals(java.lang.Object)
public final java.lang.String com.sun.proxy.$Proxy0.toString()
public final int com.sun.proxy.$Proxy0.hashCode()
public final ecut.aop.proxy.IPhone com.sun.proxy.$Proxy0.create()
由以上输出可以推测出来代理类的类名是$Proxy0,且有一个有参构造,参数是InvocationHandler类型,且有四个属性,四个方法,还继承了父类的Proxy类中的protected InvocationHandler h属性,推测其他m0,m1....都与方法相对应。$Proxy0源码可能类似于
Proxy类
public class Proxy { protected InvocationHandler h ; // 父类中 public 修饰的 和 protected 修饰 都可以被子类继承 protected Proxy( InvocationHandler h ) {
this.h = h ;
} }
$Proxy0类
package com.sun.proxy ; public class $Proxy0 extends Proxy implements AppleCompany { public $Proxy0( InvocationHandler h ){
super( h );
} private static Method m0 ;
private static Method m1 ;
private static Method m2 ;
private static Method m3 ; /* .......... */ static {
Class<?> c = $Proxy0.class ;
m0 = c.getMethod( "equals" , Object.class );
m1 = c.getMethod( "toString" );
m2 = c.getMethod( "hashCode" );
m3 = c.getMethod( "create" ); /* .......... */
} public final boolean equals( Object another ) {
Object[] args = new Object[]{ another };
return h.invoke( this , m0 , args );
} public final String toString() {
Object[] args = new Object[ 0 ];
return h.invoke( this , m1 , args );
} public final int hashCode() {
Object[] args = new Object[ 0 ];
return h.invoke( this , m2 , args );
} public final IPhone create() {
Object[] args = new Object[ 0 ];
return h.invoke( this , m3 , args );
} }
5、动态代理的实现和源码分析
查看Proxy类的newProxyInstance方法,从生成对象方法中,我们看到三个关键的地方:
- Class<?> cl = getProxyClass0(loader, interfaces);//得到代理类
- final Constructor<?> cons = cl.getConstructor(constructorParams);
- newInstance(cons, h);//将InvocationHandler h传入代理对象中
首先是通过Proxy.newProxyInstance( loader , interfaces , handler ) 将handler传入了$Proxy0 中的 InvocationHandler h属性中,然后当我们调用方法时候实际上是通过h.invoke( this , m3 , args )来实现的即调用handler里面的invoke方法,而在handler的invoke方法中通过method.invoke( target , args )方法,最终调用的是target里面的方法。
结合动态代理理解AOP相关概念
1、理解Advice测试案例
package ecut.aop.proxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class ProxyTest2 { public static void main(String[] args) { // 代理目标 ( 谁将被别人代理 )
final Object target = new FoxconnFactory(); // 代理目标 的类型 : 获得 被代理的 对象的 运行时 类型
Class<?> targetClass = target.getClass(); /** 用 代理目标 类型对应的类加载器 去加载 运行阶段动态产生的 代理类 */
ClassLoader loader = targetClass.getClassLoader() ; // 获得 代理目标 对应的 类的 "类加载器" /** 指示 将来产生 动态代理类 所需要实现的接口 */
Class<?>[] interfaces = targetClass.getInterfaces() ; // 获得 代理目标 对应的类所实现的接口 /** 请求指派器 */
InvocationHandler handler = new InvocationHandler(){
@Override
public Object invoke( Object proxy , Method method , Object[] args ) throws Throwable {
System.out.println( "方法[ " + method.getName() + " ]将要执行了" ); // Advice
Object result = method.invoke( target , args ) ; // target.create();
System.out.println( "方法[ " + method.getName() + " ]执行结束并返回了: " + result ); // Advice
return result;
}
} ; // 代理对象 ( 谁将去代理别人 ),这四个方法执行其前后就被我们拦截下来了 ,方法前后增加了输出语句,没有动方法,只是在动态代理类handler里面增加了代码
//我们所增加的代码如果按照规范来封装好就是Advice
Object proxy = Proxy.newProxyInstance( loader , interfaces , handler ) ; if( proxy instanceof AppleCompany ) {
AppleCompany ac = (AppleCompany) proxy ;
System.out.println( ac == proxy ); IPhone p = ac.create();
System.out.println( p ); System.out.println( ac.toString() ); System.out.println( ac.hashCode() ); System.out.println( ac.equals(target) );//target.equals(target);
} } }
这四个方法执行其前后就被我们拦截下来了 ,方法前后增加了输出语句,没有动方法,只是在动态代理类handler里面增加了代码 ,我们所增加的代码如果按照规范来封装好就是Advice。
理解连接点测试案例:
package ecut.aop.proxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class ProxyTest3 { public static void main(String[] args) { // 代理目标 ( 谁将被别人代理 )
final Object target = new FoxconnFactory(); Class<?> targetClass = target.getClass(); ClassLoader loader = targetClass.getClassLoader() ; Class<?>[] interfaces = targetClass.getInterfaces() ; InvocationHandler handler = new InvocationHandler(){
@Override
public Object invoke( Object proxy , Method method , Object[] args ) throws Throwable { System.out.println( "方法[ " + method.getName() + " ]将要执行了" ); // before Object result = null ;
try{
long start = System.nanoTime(); // around
result = method.invoke( target , args ) ; // 执行点
long end = System.nanoTime(); // around
System.out.println( "执行用时: " + ( end - start ) + " 毫微妙" ); // around
System.out.println( "执行后并返回: " + result); // after-returing
} catch ( Throwable t ){
System.out.println( "发生错误: " + t.getMessage() ); // after-throwing
} System.out.println( "方法[ " + method.getName() + " ]执行结束" ); // after return result;
}
} ; Object proxy = Proxy.newProxyInstance( loader , interfaces , handler ) ; if( proxy instanceof AppleCompany ) {
AppleCompany ac = (AppleCompany) proxy ;
System.out.println( ac == proxy );
//通过create调用了target中create的方法
IPhone p = ac.create();
System.out.println( p );
//代理对象 $Proxy0中的四个方法是可执行的,方法在执行时候就可以视为是一个执行点
String s = ac.toString() ;
System.out.println( s );
} } }
连接点 ( Join Point ) : 执行点 + 方位信息 所有被拦截的方法被加入了其他的方法,通过代理的方法将想要加入的想要的代码,加入的代码和原有的代码形成了连接点
执行点就是一个可以执行的方法在执行时就是一个执行点,当create方法在执行的时候就是一个执行点,方位信息就是加入Advice的位置就是方位信息,执行点加上分为信息就是连接点。
理解切点测试案例:
package ecut.aop.proxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class ProxyTest4 { public static void main(String[] args) { // 代理目标 ( 谁将被别人代理 )
final Object target = new FoxconnFactory(); Class<?> targetClass = target.getClass(); ClassLoader loader = targetClass.getClassLoader() ; Class<?>[] interfaces = targetClass.getInterfaces() ; InvocationHandler handler = new InvocationHandler(){
@Override
//只保留了before和after的方位信息,20个连接点里挑选了8个,增加了了判断语句后只对create方法增加Advice,这些筛选条件就是切点
public Object invoke( Object proxy , Method method , Object[] args ) throws Throwable { if( "create".equals( method.getName() ) ) {
System.out.println( "方法[ " + method.getName() + " ]将要执行了" ); // before
} Object result = method.invoke( target , args ) ; // 执行点 if( "create".equals( method.getName() ) ){
System.out.println( "方法[ " + method.getName() + " ]执行结束" ); // after
} return result;
}
} ; Object proxy = Proxy.newProxyInstance( loader , interfaces , handler ) ; if( proxy instanceof AppleCompany ) {
AppleCompany ac = (AppleCompany) proxy ;
System.out.println( ac == proxy ); IPhone p = ac.create();
System.out.println( p ); String s = ac.toString() ;
System.out.println( s ); System.out.println( ac.hashCode() );
} } }
切点就是筛选连接点的条件,比如增加了了判断语句后只对create方法增加Advice,这些筛选条件就是切点。
参考博客链接:
https://blog.csdn.net/pdsygt/article/details/46433537
https://blog.csdn.net/u011266694/article/details/78918394
转载请于明显处标明出处:
https://www.cnblogs.com/AmyZheng/p/9264215.html
Spring学习(六)的更多相关文章
- Spring学习(六)-----Spring使用@Autowired注解自动装配
Spring使用@Autowired注解自动装配 在上一篇 Spring学习(三)-----Spring自动装配Beans示例中,它会匹配当前Spring容器任何bean的属性自动装配.在大多数情况下 ...
- spring学习 六 spring与mybatis整合
在mybatis学习中有两种配置文件 :全局配置文件,映射配置文件.mybatis和spring整合,其实就是把mybatis中的全局配置文件的配置内容都变成一个spring容器的一个bean,让sp ...
- Spring学习六(事物管理)
参考链接 http://www.mamicode.com/info-detail-1248286.html http://www.cnblogs.com/wangdaqian/archive/2017 ...
- spring学习六
1: @Valid 注解 @NotNull(message="名字不能为空") private String userName; @Max(value=120,message ...
- spring学习六----------Bean的配置之Aware接口
© 版权声明:本文为博主原创文章,转载请注明出处 Aware Spring提供了一些以Aware结尾的接口,实现了Aware接口的bean在被初始化后,可以获取相应的资源 通过Aware接口,可以对S ...
- Spring学习(六)--渲染Web视图
一.将模型数据渲染为Html 在上一篇文章中,我们所编写的控制器方法都没有直接产生浏览器中渲染所需的HTML.这些方法只是将数据填充到模型中,然后将模型传递给一个用来渲染的视图.这些方法会返回一个St ...
- Spring学习六:自定义Event事件
Spring 中的自定义事件 编写和发布自己的自定义事件有许多步骤.按照在这一章给出的说明来编写,发布和处理自定义 Spring 事件. 步骤 描述 1 创建一个名称为 SpringExample 的 ...
- (转)MyBatis框架的学习(六)——MyBatis整合Spring
http://blog.csdn.net/yerenyuan_pku/article/details/71904315 本文将手把手教你如何使用MyBatis整合Spring,这儿,我本人使用的MyB ...
- Spring学习笔记(六)—— SSH整合
一.整合原理 二.整合步骤 2.1 导包 [hibernate] hibernate/lib/required hibernate/lib/jpa 数据库驱动 [struts2] struts-bla ...
随机推荐
- ansible基本使用(一)
ansible是什么? ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.chef.func.fabric)的优点,实现了批量系统配置.批量程序部署.批量 ...
- 使用springboot整合ActiveMQ
结构图 第一步:导入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifact ...
- matlab 中 find() 函数用法
一. 功能: 寻找非零元素的索引和值 二.相关函数语法: ind = find(X) ind = find(X, k) ind = find(X, k, 'first') ind = find(X, ...
- 【python基础语法】数据类型:数值、字符串 (第2天课堂笔记)
""" 数据类型: 一.数值类型:整数 浮点数 布尔值 二.序列类型:字符串.列表 元祖 三.散列类型:字典 集合 可变数据类型: 列表 字典 集合,可以改动内存地址数据 ...
- AcWing1296. 聪明的燕姿
聪明的燕姿 解题思路: 首先我们肯定要用到约数之和定理 但是有个问题就是要怎么用 根据经验得知,约数最多也就六七个左右,不然直接就超了s的范围.所以我们考虑用爆搜来做 但是用爆搜的话还是要优化一下思路 ...
- go cap和len的区别
首先要搞清楚容量和长度的区别: 容量是指底层数组的大小,长度指可以使用的大小 容量的用处在哪?在与当你用 appen d扩展长度时,如果新的长度小于容量,不会更换底层数组,否则,go 会新申请 ...
- Antenna Placement poj 3020
Antenna Placement Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12104 Accepted: 595 ...
- Pikachu-Sql Inject(SQL注入)
在owasp发布的top10排行榜里,注入漏洞一直是危害排名第一的漏洞,其中注入漏洞里面首当其冲的就是数据库注入漏洞.一个严重的SQL注入漏洞,可能会直接导致一家公司破产!SQL注入漏洞主要形成的原因 ...
- srpingboot web - 启动(3) 监听器
接上一篇 一. getRunListeners() 在run() 方法中调用了 getRunListeners(args) 方法, 先看一下这个方法干了什么 private SpringApplica ...
- springMVC请求访问的整个过程
//以上个随笔(springMVC项目配置文件)为基础,详述springMVC请求的整个过程流向 web.xml ...