(十九)Core Java 加载器及Spring底层AOP原理实现 (117)

 目录 :           
1 ) .  类加载器及其委托机制的深入分析

2 ) .  自定义加载器的编写原理分析

3 ) .  编写对class文件进行加密的工具类

4 ) .  编写和测试自己编写的解密类加载器

5 ) .  类加载器的一个高级问题的实验分析

6 ) .  分析代理类的作用与原理和AOP概念

7 ) .   创建动态类及查看其方法列表信息

8 ) . 创建动态类的实例对象及调用其方法

9 ).   完成InvocationHandle对象的内部功能

10 ). 分析InvocationHandler对象的运行原理

11 ). 总结分析动态代理类的设计原理与结构

12 ). 编写可生成代理和插入通告的通用方法

13 ). 实现类似spring的可配置的AOP框架






 


     一 .   类加载器及其委托机制的深入分析

1 ) . 明确 : 

1.1 类加载器是什么? 

[1] 类加载器本质也是java类,用来加载其他类,那类加载器是谁加载的呢? 他本身无需加载,嵌套在虚拟机上,底层是C++写的,名字叫  BootStrap

1.2 类加载器的作用?

[1]类加载器就是将用到的某个类的字节码文件从硬盘加载进内存,以可视化的方式展现的过程

1.3 java虚拟机中的类加载器了解?

[1] Java虚拟机中可以安装多个类加载器

[2] 系统默认三个主要类加载器,每个类负责加载特定位置:  BootStrap , ExtClassLoader,AppClassLoade 

2 ) . Demo : 

package   cn.ittext.day02;
/**
*   @author   winter
*   @Date     2018年3月29日下午9:24:11
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe   类功能描述
*/
public   class   ClassLoaderTest {
        public   static   void   main(String[]   args )
       {
             
              /**
              *
              * 庖丁解牛 :
              *
              * 1. 三种不同的加载器
              *
              * [1] Bootstrap
              *
              * [2] ExtClassLoader
              *
              * [3] AppClassLoader
              *
              *
              * 优先级是  [1] <-- [2] <-- [3]
              *
              *
              * 2.如何自定义加载器
              *
              * [1] 通过classLoader类,作为类加载器的子类从而实现自定义加载器
              *
              * 3.类加载器的委托机制
              *
              * [1] 无论是哪个类加载器加载,最先去判断是否可加载的加载器都是 Bootstrap,他加载不了再向下尝试
              *
              * 4.问题 : 当虚拟机要加载一个类时,到底先派出那个类加载器进行加载呢?
              *
              * [1] 首先得有 总的加载器 ,因此 当前线程的类加载器去加载线程中的第一个类  null
              *
              * [2] 然后通过委托机制依次从总的加载器向下传递的去类加载其指定的目录进行加载直到找到可加载的类  :  Bootstrap    -->   ExtClassLoader --> AppClassLoader
              *
              *
              *   ps   :
              *
              *    (1) 若类A引用了类B,Java虚拟机则使用加载类A的加载器去加载类B
              *
              *    (2) 还可通过ClassLoader.loadClass()来直接指定某个加载器去加载某各类
              *   
              *    (3) 我们还可通过自定义类加载对指定目录进行加载
              *
              */
             
             
             ClassLoader   systemName   = System. class .getClassLoader();
             
        //      sop ("System系统类的类加载器是什么:"+systemName);  //空代表是 顶级的类加载器是 Bootstrap ,用来加载系统类
             
             String   ownName   = ClassLoaderTest. class .getClassLoader().getClass().getName();
             
        //      sop ("ClassLoaderTest自定义类的类加载器是什么:"+ownName); //用来加载ClassPath指定的所有jar和目录 -->AppClassLoader
             
             
             
              /**
              * 遍历出所有的类加载器
              *
              */
             ClassLoader   classLoader   = ClassLoaderTest. class .getClassLoader();    //获取其中一个类加载器
             
              while ( classLoader != null )
             {
             
                    String   name   =   classLoader .getClass().getName();    //获取其类加载其的名字
                    
                     sop ( name );
                    
                     classLoader   = classLoader .getParent();    //不断的向上获取直到获取到顶级加载器也就是Null后停止
                    
             }
              sop ( classLoader );    //输出顶级加载器
             
             
 
       }
        public   static   void   sop(Object   obj )
       {
             System. out .println( obj );
       }
}
 
 

3 ) .  类加载器图解 :



小结 :  

             1.  了解类加载器的委托机制,明白加载器的优先级
        
           2.  记得每个不同的加载器所加载的目录文件

           3. 我们还可通过自定义加载器去加载我们指定的目录,这样其他人没有我们的加载器是不能加载我们的代码的

       
 

       二.  自定义加载器的编写原理分析


1 ) . 

2 ) . 自定义加载器的须知 : 

2.1 首先自定义加载器先继承ClassLoader

2.3 其次覆盖findClass方法  -->用来获取字符式的字节码  :   若 需要更改委托机制的优先级, 则也可覆盖掉 loadClass方法

2.4 最后编写defineClass方法 --> 用来将字符的字节码转化为类的实例

3 ) .  自定义加载器步骤:

3.1 编写一个对文件内容进行简单加密的程序

3.2 编写了一个自己的类装载器,可实现对加密过的类进行装载和解密

3.3 编写一个程序调用类加载器加载类,在源程序中不能用该类名定义引用变量,因为编译器无法识别这个类,程序中可以出了使用classLoader.load方法之外,还可使用设置线程的上下

文类加载器或者系统类加载器,然后再使用Class.forName

4 ) . 实验步骤 : 

4.1 对不带包名的class文件进行加密,加密结果存放到另外一个目录,例如 : java MyClassLoader  MyTest class F:\itcast

4.2 运行加载类的程序,结果能够被正常加载,但打印出来的类加载器名称为AppClassLoader: java MyClassLoader MyTest F:\itcast

4.3 用加密后的类文件替换ClassPath环境下的类文件,再执行上一步操作就出现问题了,错误说明是AppClassLoader类装载器装载失败

4.4 删除Class文件,重新进行生成


小结 :  

             1.  模板方法设计模型就是 提供通用框架, 而后填充实现具体细节的过程就是模板设计方式
        
   

      三.  编写对class文件进行加密的工具类

1 ) . Demo :

package   cn.ittext.day02;
import   java.io.FileInputStream;
import   java.io.FileOutputStream;
import   java.io.IOException;
import   java.io.InputStream;
import   java.io.OutputStream;
/**
*   @author   winter
*   @Date     2018年3月30日上午10:13:20
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe   自定义类加载器并实现加密
*/
public   class   MyClassLoader {
        public   static   void   main(String[]   args )   throws   IOException
       {
             
              /**
              *
              * 庖丁解牛: 
              *
              * [1] 加密解密算法测试   -->   通过异或的方式进行加密,再次异或即可解密
              *
              *
              * [2] 加密工具类的封装
              */
             
              //加密
          /*    FileInputStream   fis   =new FileInputStream("S:\\develop\\DevWorkSpace\\WebWorkSpace2\\ javapractice \\ src \\ cn \\ ittext \\day02\\Person.java");
             
              FileOutputStream   fos   =new FileOutputStream("S:\\develop\\DevWorkSpace\\WebWorkSpace2\\ javapractice \\ src \\ cn \\ ittext \\encryptClass\\encryptClass.file");
             
               encryptClass( fis , fos );*/
             
              //解密
              FileInputStream   fis   = new   FileInputStream( "S:\\develop\\DevWorkSpace\\WebWorkSpace2\\javapractice\\src\\cn\\ittext\\encryptClass\\encryptClass.class" );
              
              FileOutputStream   fos   = new   FileOutputStream( "S:\\develop\\DevWorkSpace\\WebWorkSpace2\\javapractice\\src\\cn\\ittext\\encryptClass\\DecodeClass.java" );
              
               encryptClass ( fis , fos ); 
              
              
              
              
       
               new   entryClassUtils( fis , fos );    //加密工具类的方式
              
       }
       
        public   static   void   encryptClass(InputStream   ips   , OutputStream   ops )   throws   IOException
       {
              int   temp =0;
 
              while (( temp = ips .read())!=-1)
             {
                     ops .write( temp ^0xff);
 
             }
       }
       
        public   static   void   sop(Object   obj )
       {
             System. out .println( obj );
       }
}
 
 

2 ) . 加密工具类:

package   cn.ittext.day02;
import   java.io.IOException;
import   java.io.InputStream;
import   java.io.OutputStream;
/**
*   @author   winter
*   @Date     2018年3月30日上午11:29:22
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe   类功能描述
*/
public   class   entryClassUtils {
        private   InputStream    ips ;
       
        private   OutputStream   ops ;
       
 
        public   entryClassUtils(InputStream   ips , OutputStream   ops )   throws   IOException
       {
              super ();
              this . ips   =   ips ;
              this . ops   =   ops ;
             
              encryptClass ( ips , ops );
       }
        public   static   void   encryptClass(InputStream   ips   , OutputStream   ops )   throws   IOException
       {
              int   temp =0;
 
              while (( temp = ips .read())!=-1)
             {
                     ops .write( temp ^0xff);
 
             }
       }
       
        public   static   void   sop(Object   obj )
       {
             System. out .println( obj );
       }
}
 
 
 

小结 :  

             1.  有包名的类不可调用无包名的类
        
 
 

      四. 编写和测试自己编写的解密类加载器  -->未能实现,以下代码不可用

1 ) . 类加密文件 : 

package   cn.ittext.day02;
import   java.io.IOException;
import   java.io.InputStream;
import   java.io.OutputStream;
/**
*   @author   winter
*   @Date     2018年3月30日上午11:29:22
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe   类加密
*/
public   class   entryClassUtils {
        private   InputStream    ips ;
       
        private   OutputStream   ops ;
       
 
        public   entryClassUtils(InputStream   ips , OutputStream   ops )   throws   IOException
       {
              super ();
              this . ips   =   ips ;
              this . ops   =   ops ;
             
              encryptClass ( ips , ops );
       }
        public   static   void   encryptClass(InputStream   ips   , OutputStream   ops )   throws   IOException
       {
              int   temp =0;
 
              while (( temp = ips .read())!=-1)
             {
                     ops .write( temp ^0xff);
 
             }
       }
       
        public   static   void   sop(Object   obj )
       {
             System. out .println( obj );
       }
}
 
 

2 ) . Person类文件

package   cn.ittext.encryptClass;
import   java.util.Date;
/**
*   @author   winter
*   @Date     2018年3月29日下午5:12:32
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe   类功能描述
*/
public   class   Person   extends   Date{
       
        private   Integer   id ;
        private   String   name ;
        private   Integer   age ;
        public   Integer getId() {
              return   id ;
       }
        public   void   setId(Integer   id ) {
              this . id   =   id ;
       }
        public   String getName() {
              return   name ;
       }
        public   void   setName(String   name ) {
              this . name   =   name ;
       }
        public   Integer getAge() {
              return   age ;
       }
        public   void   setAge(Integer   age ) {
              this . age   =   age ;
       }
        public   Person(Integer   id , String   name , Integer   age ) {
              super ();
              this . id   =   id ;
              this . name   =   name ;
              this . age   =   age ;
       }
        @ Override
        public   String toString() {
              return   "Person [id="   +   id   +   ", name="   +   name   +   ", age="   +   age   +   "]" ;
       }
       
 
 
       
}
 
 

3 ) .  加载器文件

 package cn.ittext.day02;
import   java.io.ByteArrayOutputStream;
import   java.io.FileInputStream;
import   java.io.IOException;
 
/**
*   @author   winter
*   @Date     2018年3月30日下午2:04:31
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe   自定义类加载器
*/
public   class   decodeMyClassLoader   extends   ClassLoader
{
        private   String   classDir   //传入的目录地址
       decodeMyClassLoader()
       {
             
       }
       
       decodeMyClassLoader(String   classDir )
       {
              this . classDir = classDir ;
       }
 
        @Override
        protected   Class<?> findClass(String   name )   throws   ClassNotFoundException
       {
             String   fileName   = getFileName( name );    //获取文件地址
             
          try   {
                    
                byte []   bytes   = getClassBytes( fileName );    //  通过文件地址获取其中的字节码
             
              return   defineClass ( bytes , 0,   bytes . length )   //通过自定义加载器将字节码数据返回
                    
             }   catch   (IOException   e ) {
             
                     e .printStackTrace();
             } 
          
              return   super .findClass( name );       //通过父类的加载器将字节码数据返回
       }
       
        private   byte [] getClassBytes(String   fileName )   throws   IOException
       {
             FileInputStream   fis   = new   FileInputStream( fileName );     //源
             
             ByteArrayOutputStream   baos   = new   ByteArrayOutputStream();    //目标
             
              new   entryClassUtils( fis ,   baos );    //解密
             
              fis .close();
 
              byte []   byteArray   =   baos .toByteArray();    //换算成数组的形式
             
              return   byteArray ;
       }
        //获取文件
        private   String getFileName(String   name ) {
 
          String   pathClass   =   classDir + "\\" + name + ".class"   //目的+文件名 = 文件地址
             
              return   pathClass ;      //返回文件全地址
             
       }
        public   static   void   sop(Object   obj )
       {
             System. out .println( obj );
       }
}
 
 


4 ) . 测试文件

     package   cn.ittext.day02;
import   java.io.FileNotFoundException;
import   java.io.IOException;
import   java.util.Date;
/**
*   @author   winter
*   @Date     2018年3月30日下午2:37:19
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe   这是一个测试类
*/
public   class   entryDemo {
        public   static   void   main(String[]   args )   throws   FileNotFoundException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
       {
             
          /*    File source =new File("S:\\develop\\DevWorkSpace\\WebWorkSpace2\\ javapractice \\ src \\ cn \\ ittext \\encryptClass\\Person.java");
             
             File target =new File("S:\\develop\\DevWorkSpace\\WebWorkSpace2\\ javapractice \\ itcast \\Person.class");
             
             new entryClassUtils(new FileInputStream(source), new FileOutputStream(target));*/
             
             
                Class   loadClass   =   new   decodeMyClassLoader( "itcast" ).loadClass( "Person" );    //传入自定义目录和加载的对象
 
              Date   newInstance   = (Date) loadClass .newInstance();    //实例化
             
                sop ( newInstance );
       }      
                                                                                                                              
        public   static   void   sop(Object   obj )
       {
             System. out .println( obj );
       }
}
 
 



小结 :  

             1.  通过将自定义加载器挂到加载器的体系中,从而实现特定加载器去加载特定目录下的文件
        
         
       

     五 .  类加载器的一个高级问题的实验分析


3 ) .  小知识:

3.1 Servlet是被Tomcat提供的类加载器加载的

3.2 WEB项目与Java项目中class的区别在于 , web中的class是可被 servlet 加载的class, java的class 是被虚拟机加载的class

4 ) . 结论 :

4.1 Servlet有着自己的加载器, 是 apache 旗下的,当出现500等页面找不到的问题时,也有可能是 加载器的问题

 小结 :  

             1.  Tomcat是非常多的类加载器的集合,Tomcat是服务器
 

       六. 分析代理类的作用与原理和AOP概念


1 ) . 代理  :

1.1 生活中的代理 : 

[1]  A客户去 B商户 购买 一件商品, 来回用时 2小时 , 商品1950+ 油费50  共计  2000元  

[2] A客户去 B商户 购买一件商品,全权交由代理商送货上门 , 商品1950元 + 服务费 50元 共计 2000元    

[3] 比较 : 代理购买方案 显然 比 传统购买方案要 省时,  时间如同金钱

1.2 程序中的代理 :  -->在程序扩展方面的应用

[1] 直接方式 : A客户端 直接 调用 B 服务端 代码 进行 服务   

[2] 代理方式 :  

(1) A客户端 直接调用  B服务端的代理类  :  创建一个代理 类  实现 B服务端的 接口 ,从而 将B服务端的 原始方法 实现 ,而后对代理类 进行 方法完善 即可  

(2) 采用工厂模式和配置文件的方式 进行管理 ,则无需修改客户端程序,直接在配置文件中修改是使用目标类还是代理类  

(3) 优势 : 灵活性,已修改,可扩展



 

2 ) . AOP (面向切面编程) -- > 面向代理编程 : 

2.1 系统中存在交叉业务,交叉业务就是要切入到系统中的一个方面,如图所示 : 




2.2 面向切面编程就是 将交叉业务 模块化,独立出来,提供公共访问的方式

2.3 如何实现切面?  就是通过代理技术的方式, 因此 代理是实现AOP功能的核心关键技术


3 ) .  什么是动态代理类?

3.1 JVM可以再运行期间动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类

3.2 JVM生成的动态类必须实现一个或多个接口,因此JVM生成的动态类只能用作具有相同接口的目标类的代理

3.3 若一个没有实现接口的类要生成动态代理类,则通过CGLIB库动态生成一个类的子类

4 ) . 代理类各个方法中除了实现目标类的相应方法和返回相应结果之外,还可在代理方法中的如下四个位置加上系统完善功能代码:

4.1 在调用目标方法之前

4.2 在调用目标方法之后

4.3 在调用目标方法前后

4.4 在处理目标方法异常的catch块中


小结 :  

             1.  代理就是代替自己理解并完成任务的一种方式,优势是节省了自身时间
        
           2.  交叉业务就是 每个模块都需要的通用业务 ,将其 分离出来,以公地的形式出现,而后 贯穿到每个模块中

           3. 如果我们需要使用的那个类没有接口, 无法进行方法的实现, 那么就是用CGLib进行动态的创建子类

 


      七. 创建动态类及查看其方法列表信息

1 ) . 核心内容  :  通过 JVM生成动态类 并获取其 动态类的所有 构造函数和所有方法
  
2 ) . Demo :

package   cn.ittext.day03;
import   java.lang.reflect.Constructor;
import   java.lang.reflect.Executable;
import   java.lang.reflect.Method;
import   java.lang.reflect.Proxy;
import   java.util.Collection;
/**
*   @author   winter
*   @Date     2018年3月31日下午1:46:58
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe   创建collection的动态类并获取动态类中的构造函数和所有方法
*/
public   class   ProxyTest {
        public   static   void   main(String[]   args )
       {
              /**
              * 庖丁解牛 :
              *
              * [1] 如何 获取 collection的动态类
              *
              * [2] 如何获取动态类中的构造函数 和参数列表
              *
              * [3] 如何获取动态类中的所有方法 和参数列表
              *
              *   ps   : 以上的动态类指代理类
              *
              */
             
             
             
              //通过 Proxy 类调用获取代理类的方法getProxyClass ,其中传入 要获取的 类的 加载器 和 类的 字节码文件 ,之后返回 其代理类的字节码文件
              Class   proxyClazz   = Proxy. getProxyClass (Collection. class .getClassLoader(), Collection. class ); //[1]  
             
              getConstructors ( proxyClazz );   //获取其动态类中的所有构造函数 和参数列表  //[2]
       
              getMethods ( proxyClazz );    //获取其动态类中的所有方法 和参数列表         //[3]  
             
       }
        private   static   void   getMethods( Class   proxyClazz )
       {
              sop ( "--------------------------beagin method list--------------------------" );
             StringBuilder   sbMethod   = new   StringBuilder();
             
              //获取collection的代理类的所有方法
             Method[]   methods   =   proxyClazz .getMethods();
             
              for (Method   method : methods )
             {
                     String   conname   =   method .getName();
                    
                       sbMethod .append( conname );
                    
                       sbMethod .append( "(" );
                    
                            getParameter ( sbMethod ,   method );   //获取其 方法中的参数列表
                    
                       sbMethod .append( ")" );
                    
                       sbMethod .append( "\r\n" );
             }
             
                sop ( sbMethod .toString()); //输出 StringBuilder中方法的内容
       }
        private   static   void   getConstructors( Class   proxyClazz )
       {
             
              //获取collection的代理类的所有构造函数
              Constructor []   constructors   =   proxyClazz .getConstructors();
             
             StringBuilder   sbConstru   = new   StringBuilder();
             
              sop ( "--------------------------beagin constructor list--------------------------" );
             
              //迭代代理类中的构造函数
               for ( Constructor   constructor : constructors )
             {
                     String   conname   =   constructor .getName();  
                       sbConstru .append( conname );
                       sbConstru .append( "(" );
             
                            getParameter ( sbConstru ,   constructor );      //获取其 构造函数中的参数列表
                    
                     sbConstru .append( ")" );
                           
                                sop ( sbConstru .toString());   //输出 StringBuilder中构造函数的内容
             }
       }
 
        //专门用来获取构造函数/方法的参数名 并将 参数名放入 StringBuilder的方法  -->这是公用方法
        private   static   <T>   void   getParameter(StringBuilder   sb , T   method ) {
              Class []   classparameters   = ((Executable)   method ).getParameterTypes();
             
                for ( Class   parameterclazze   : classparameters )
              {
                     String   parametername   =   parameterclazze .getName();
                    
                       sb .append( parametername + "," );
              }
                if ( classparameters   != null   &   classparameters . length   !=0)
                sb .deleteCharAt( sb .length()-1);
       }
 
        public   static   void   sop(Object   obj )
       {
             System. out .println( obj );
       }
}
 
 
 
 

小结 :  

             1.  在单线程的情况下,进行动态字符串拼接用StringBuilder ,在多线程的情况下,进行动态字符串拼接用StringBuffer
     
     八 创建动态类的实例对象及调用其方法

1 ) . 实例化动态类 并 调用 动态类中的方法 用以实验

2 ) . Demo:


package   cn.ittext.day03;
import   java.lang.reflect.Constructor;
import   java.lang.reflect.InvocationHandler;
import   java.lang.reflect.InvocationTargetException;
import   java.lang.reflect.Method;
import   java.lang.reflect.Proxy;
import   java.util.ArrayList;
import   java.util.Collection;
import   java.util.Iterator;
/**
*   @author   winter
*   @Date     2018年3月31日下午3:10:03
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe   创建collection的动态类,并使用动态类进行相关操作
*/
public   class   ProxyTest01 {
        public   static   void   main(String[]   args )   throws   NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
       {
              //实现InvocationHandler接口的类,用来作为实例化代理类的对象参数
              class   MyInvocationHandler   implements   InvocationHandler
             {
                     @Override
                     public   Object invoke(Object   proxy , Method   method , Object[]   args )   throws   Throwable {
                            return   null ;
                    }
             }
             
              //获取collection动态类的字节码文件
              @SuppressWarnings ( "rawtypes" )
             Class   proxyClazz   = Proxy. getProxyClass (Collection. class .getClassLoader(), Collection. class );
             
              //通过字节码文件获取其构造函数
              @SuppressWarnings ({   "unchecked" ,   "rawtypes"   })
             Constructor   constructorClazz   =   proxyClazz .getConstructor(InvocationHandler. class ); 
             
              //通过构造函数进行实例化,但构造函数有参数,需要将InvocationHandler接口作为参数传入,因此我采用了实现此接口,将其实现类传入
              @SuppressWarnings ({   "unchecked" ,   "rawtypes"   })
             Collection<String>   collProxy   = (Collection)   constructorClazz .newInstance( new   MyInvocationHandler());
 
              //通过实例化ArrayList构造函数
              collProxy =    new   ArrayList() ;
 
              //使用collection的代理类调用方法
               collProxy .add( "A" );
              collProxy .add( "B" );
              collProxy .add( "C" );
             
              //迭代集合中的元素
              for (Iterator<String>   it   =   collProxy .iterator(); it .hasNext();)
             {
                     sop ( it .next());
             }
             
             
             
              /**
              *
              *
              * 庖丁解牛 :
              *
              * [1] 获取代理类的字节码
              *
              * [2] 获取代理类的构造函数的字节码
              *
              * [3] 通过构造函数字节码实例化代理类对象的方式   --> 这里需要传入对象参数InvocationHandler
              *
              * [4] 通过将实例化对象接口的可实例化子类进行关联,从而进行增加操作并迭代
              *
              *
              * 小结:
              *
              * [1] 我们可发现动态类中有其目标类中的所有方法,可直接拿来使用
              *
              * [2] 想要实例化代理类,需要将构造函数中传入 InvocationHandler 接口的实现类才行
              *
              *
              *
              */
       
       }
        public   static   void   sop(Object   obj )
       {
             System. out .println( obj );
       }
}
 

 

 
小结 :  

             1.  反射获取方法的时候出入的是方法的参数类型,当实例化方法时传入的是 类型的具体值
        
           2.  当实例化一个对象将其变量打印输出返回null时, 只能说明其 对象的 toString ()方法返回的null,因为若对象为NUll则会直接报告空指针异常

    

     九 .  完成InvocationHandle对象的内部功能

1 ) . 代理类的三种实现方式 :  


package cn.ittext.day03;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/**
* @author  winter
* @Date    2018年3月31日下午4:13:39
* @tel        1394869214@qq.com
* @version 1.0
* @describe 实现代理类的三种方式
*/

public class ProxyTest03 {

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException
    {
        
        
        /**
         *
         *
         *  庖丁解牛 : 代理类的三种实现方式
         *  
         *          [1] 自定义InvocationHandler的实现类的方式
         *  
         *       [2] InvocationHandler的匿名内部类的方式
         *  
         *          [3] 直接使用Proxy调用其方法newProxyInstance(iterfaceClassLoader,iterface,InvocationHandler)   ---> 要用就用第三种
         *
         *
         *
         */
        
        //方式一: 自定义InvocationHandler的实现类的方式  ----------------------------------------------------------------------------
            /*  class MyInvocationHandler implements InvocationHandler
                {
                    ArrayList arr =new ArrayList(); //一个实例化类型 用来让 代理类指定
                    
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
                    {
                        //实例化前的代理类只是个接口,只有实例化后才是一个实力类,才能被应用
                        
                        Object invoke = method.invoke(arr, args);  //通过一个实体类调用 代理类,也就是 为是实例化代理类
                        
                        return invoke;  //返回实例化后的代理类
                    }
                }
                
                //获取collection动态类的字节码文件
                Class proxyClazz1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
                //通过字节码文件获取其构造函数
                Constructor constructorClazz = proxyClazz1.getConstructor(InvocationHandler.class);  
                //通过构造函数进行实例化,
                Collection<String> collProxy = (Collection) constructorClazz.newInstance(new MyInvocationHandler());
        
                collProxy.add("A");
                collProxy.add("B");
                collProxy.add("C");
                
                //迭代集合中的元素
                for(Iterator<String> it = collProxy.iterator();it.hasNext();)
                {
                    sop(it.next());
                } */
                
                
        //方式二:InvocationHandler的匿名内部类的方式  ----------------------------------------------------------------------------
        /*        
                //获取collection动态类的字节码文件
                Class proxyClazz2 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
                //通过字节码文件获取其构造函数
                Constructor constructorClazz = proxyClazz2.getConstructor(InvocationHandler.class);  
                //通过构造函数进行实例化,
                @SuppressWarnings("unchecked")
                Collection<String> collProxy = (Collection) constructorClazz.newInstance(new InvocationHandler()
                {
                    ArrayList arr =new ArrayList();
                    
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        
                        Object invoke = method.invoke(arr, args);
                        
                        return invoke;
                    }
        
                    
                });
        
                collProxy.add("A");
                collProxy.add("B");
                collProxy.add("C");
                
                //迭代集合中的元素
                for(Iterator<String> it = collProxy.iterator();it.hasNext();)
                {
                    sop(it.next());
                }*/
                
                
                
        //方式三:直接使用Proxy调用其方法newProxyInstance()的方式 +InvocationHandler的匿名内部类的方式 ----------------------------------------------------------------------------
                        
                        
            
        //获取collection的代理类ArrayList的方式
/*        @SuppressWarnings("unchecked")
        Collection<String> collProxy3 =(Collection<String>) Proxy.newProxyInstance(
            Collection.class.getClassLoader(),  
            new Class[] {Collection.class},
            new InvocationHandler()
            {
                ArrayList<String> arr =new ArrayList<String>();
                
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
                {
                    Object invoke = method.invoke(arr, args);
                    
                    return invoke;
                }
            });
        
                collProxy3.add("A");
                collProxy3.add("B");
                collProxy3.add("C");
                
                //迭代集合中的元素
                for(Iterator<String> it = collProxy3.iterator();it.hasNext();)
                {
                    sop(it.next());
                }
        */
        
        
    }

    public static void sop(Object obj) {
        System.out.println(obj);
    }
}





 
 

 
 
 
小结 :  

             1.  如若某个方法需要将接口作为参数传入的话,有两种方式  一将自定义的一个实现了此接口的实现类传入 , 二 将 此接口以匿名内部类的方式传入
        
           2.  通过proxy代理类的方法 newProxyInstance() 直接实例化一个 相关 接口的 代理类 ,并传入 InvocationHandler 对其进行管理

  

       十. 分析InvocationHandler对象的运行原理


1 ) . InvocationHandler 对象 其中的 invoke  如同代理的切面 ,  可直切 其代理对象的 方法内部或外部 

2 ) . Demo:

package   cn.ittext.day03;
import   java.lang.reflect.InvocationHandler;
import   java.lang.reflect.Method;
import   java.lang.reflect.Proxy;
import   java.util.ArrayList;
import   java.util.Collection;
import   java.util.Iterator;
/**
*   @author   winter
*   @Date     2018年3月31日下午6:10:18
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe   剖析实现代理类的第三种方式
*/
public   class   ProxyTest04 {
        public   static   void   main(String[]   args ) {
             
             
              /**
              *
              * 庖丁解牛: 剖析实现代理类的第三种方式  :   proxy 类中的 newProxyInstance()方法
              *
              *     invoke(Object   proxy , Method method, Object[]   args )
              *
              * [1]   proxy     --> 调用哪个对象
              *
              * [2] method    --> 调用对象的哪个方法
              *
              * [3]   args      --> 传递的哪个参数
              *
              *
              * 委托给InvocationHandler的方法有 :  equals , hashCode,toString
              *
              *
              * 小结 :
              *
              * [1] 我们可在invoke () 方法中 对 add() 方法的前后添加完善代码
              *
              * [2] 我们还可在invoke()方法中 对 add()方法的参数值 进行过滤等操作
              *
              * [3] 总之我们可在 invoke ()方法中对 代理类所调用的任何方法进行完善改进等操作
              *
              */
             
                           
       
// 通过 InvocationHandler作为代理类ArrayList作为目标类的方式
        @SuppressWarnings ( "unchecked" )
       Collection<String>   collProxy3   =(Collection<String>) Proxy. newProxyInstance (
       Collection. class .getClassLoader(), 
        new   Class[] {Collection. class },
        new   InvocationHandler()    //代理类
       {
             ArrayList<String>   target   = new   ArrayList<String>();    //目标类
       
              @Override   //这里的method 就是 下边的add
              public   Object invoke(Object   proxy , Method   method , Object[]   args )   throws   Throwable
             {
                    
                     sop ( "开始计时:.................." );
                     long   startTime   =System. currentTimeMillis ();
                    
                    Object   invoke   =   method .invoke( target ,   args );     //将add()方法的运行指定到 目标类,然后运行
                    
                    
                     long   endTime   =System. currentTimeMillis ();
                    
                     sop ( "结束计时:" +( endTime - startTime ));
                    
                     return   invoke ;
             }
       });
              collProxy3 .add( "A" );      //在这里每add一次,上边的 invoke 就运行一次  ,这些值添加到目标类中
              collProxy3 .add( "B" );
              collProxy3 .add( "C" );  
             
              //迭代集合中的元素
              for (Iterator<String>   it   =   collProxy3 .iterator(); it .hasNext();)
             {
                     sop ( it .next());
             }
 
}
        public   static   void   sop(Object   obj ) {
             System. out .println( obj );
       }
}
 
 

 

小结 :  

             1.  无论是代理类调用哪个方法都会走 匿名内部类InvocationHandler中的invoke()方法   ,从而指定 调用方法的 目标类是哪一个     ,因此我们可明白 invoke ()  就是 对 接口对象的代理类进行操作的 一把 切面刀 
     


      十一. 总结分析动态代理类的设计原理与结构

1 ) .Demo : 

    见下一章实现  动态代理 

2 ) . 描述 : 

2.1 流程 :  客户端调用接口方法 --> 接口方法 转交代理类 InvocationHandler去调取--> 代理类通过invoke() 方法 将调取的方法与指定目标类 相关联,通过目标类运行并返回结果 , 并且可在 invoke 方法中 对 原有方法进行改善  --> >代理类 InvocationHandler将返回值   返回到 目标类中

2.2 关系 解析 :  

[1] 接口中植入了 InvocationHandler,因此 InvocationHandler可随意访问 接口中的方法  

[2] 目标类也是接口 的 子类,因此 自然也具有 接口的方法

[3] 客户端调用 接口 , 接口 转交 代理类 InvocationHandler , 代理类 再次转交 目标类 即可 ,然后 将值 返回到 接口实例化对象中
 
3 ) . 动态代理图解 :

 

小结 :  

             1.  javaScript和 python 支持动态语言,java不支持动态语言  
        
           2.  将代码封装进对象,将对方放入invoke即可实现 , 在调用相关方法时 将灵活调用其它方法(log())

           3. 动态代理的核心 在invoke方法中 , 其参数值需传入两个对象 ,一个是  目标类对象 用来执行原有方法,  一个是系统类对象封装了需要进行切面的方法(也就是通用方法)

        

     十二 编写可生成代理和插入通告的通用方法  --> 以下有动态代理的方法

1 ) . Demo : 

package   cn.ittext.day03;
import   java.lang.reflect.InvocationHandler;
import   java.lang.reflect.Method;
import   java.lang.reflect.Proxy;
import   java.util.ArrayList;
import   java.util.Collection;
import   java.util.Iterator;
/**
*   @author   winter
*   @Date     2018年3月31日下午10:37:16
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe   实现AOP原理
*/
public   class   ProxyTest05 {
        public   static   void   main(String[]   args )
       {
              /**
              * 庖丁解牛 :
              *
              *  [1] 将代理的方法抽取出 通用型的代理方法
              * 
              *  [2] 写出插入通告的通用方法并作出测试
              */
             
              // primitive();
             
              final   ArrayList<String>   target   = new   ArrayList<String>();     // 目标类
                    
              @SuppressWarnings ( "unchecked" )
             Collection<String>   colProxy   = (Collection<String>)   getProxy ( target , new   Adtives());     //将目标类 放入代理 类中 用来 实现 AOP的操作
             
              colProxy .add( "A" );
             
              colProxy .add( "S" );
             
              colProxy .add( "D" );
             
             
              for (Iterator<String>   it   = colProxy .iterator();   it .hasNext();)
             {
                     sop ( it .next());
                    
             }
             
       }
       
       
        //用来获取代理类的方法 : 这是 将原始代理的核心代码抽取过后的代码  -->以下使用了代码重构
        private   static   Object getProxy( final   Object   target   , final   Adtive   adtive ) {
             Object   colProxy   =Proxy. newProxyInstance (
                            target .getClass().getClassLoader(),        //动态获取 接口的 加载器
                            target .getClass().getInterfaces(),              //动态的活期 接口
                            new   InvocationHandler() {                //代理类的管理者
                           
                            @Override
                            public   Object invoke(Object   proxy , Method   method , Object[]   args )   throws   Throwable
                           {
                                  /*
                                  * 在这里边有先后顺序的是 beforeMethod 和 afterMethod方法, invoke 方法永远都是最后执行 的
                                  *
                                  */
                                  adtive .beforeMethod();  
                                 
                                 Object   invoke   =   method .invoke( target ,   args );
                           
                                  adtive .afterMethod();
                                 
                                  return   invoke ;
                           }
                    });
             
             
              return   colProxy ;
       }
       
       
        //---------------------------------------------------------------------------------------------
       
       
        //原始的 collection 代理类 实现核心逻辑
        /* public static void primitive()
       {
             
             
             Collection colProxy =(Collection)Proxy.newProxyInstance(
                           Collection.class.getClassLoader(),
                           new Class[]{Collection.class},
                           new InvocationHandler() {
                           
                           ArrayList target =new ArrayList();
                    
                           @Override
                           public Object invoke(Object   proxy , Method method, Object[]   args ) throws Throwable
                           {
                                 Object invoke = method.invoke(target,   args );
                                 
                                 return invoke;
                           }
                    });
                    
                           colProxy.add("A");
                           colProxy.add("S");
                           colProxy.add("D");
                           
                           
                           for(Iterator it =colProxy.iterator(); it.hasNext();)
                           {
                                 
                                  sop (it.next());
                                 
                           }
                           
             
       }
*/
        public   static   void   sop(Object   obj )
       {
             System. out .println( obj );
       }
}
 
 

2 ) . Iterface 

package   cn.ittext.day03;
/**
*   @author   winter
*   @Date     2018年3月31日下午11:08:54
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe 切面接口
*/
public   interface   Adtive
{
       
        void   beforeMethod();
       
        void   afterMethod ();
       
}
 
 

3 ) .  IterfaceImpl

package   cn.ittext.day03;
/**
*   @author   winter
*   @Date     2018年3月31日下午11:08:39
*   @tel     1394869214 @qq.com
*   @version   1.0
*   @describe 切面接口实现类
  */
public   class   Adtives   implements   Adtive{
        @Override
        public   void   beforeMethod()
       {
             
             System. out .println( "start.................." );
       
       }
        @Override
        public   void   afterMethod()
       {
             System. out .println( "end.................." );
       }
       
}
 
 

 
 
小结 :  

             1.  AOP最重要的部分就是 动态 代理的实现 ,然后 通过 对象的方式插入通告 提供 便捷性

  2.  动态代理方法的角度最重要的两部分就是 :

[1]  newProxyInstance  ,通过这个方法 将 目标类接口加载器 ,目标类接口 和 InvocationHandler 代理类的管理者 关联到一起

[2] InvocationHandler ,通过 这个 类的invoke ()   调用目标方法  和 实现 目标方法前后 的控制
        
       
          

     十三 .  实现类似spring的可配置的AOP框架

1 ) . Demo:

1.1 beanFactory

package  cn.ittext.day3.aopframework;
import  java.io.IOException;
import  java.io.InputStream;
import  java.util.Properties;
import  cn.ittext.day3.Adtive;
/**
@author   winter
@Date     2018年4月1日下午1:45:25
@tel     1394869214 @qq.com
@version  1.0
@describe  Bean的实例化工厂
*/
public   class  BeanFactory {
       
       Properties  properties  =  new  Properties();    //创建一个资源文件引用,用来接收 输入流的数据
       
        public  BeanFactory(InputStream  ips )
       {
              try  {
                     properties .load( ips );    //将输入流的数据 放入 properties 文件中 ,因此 properties 是键值对 ,后期好获取值
             }  catch  (IOException  e ) {
                     e .printStackTrace();
             }
       }
       
       
        public  Object getBean(String  name )  
       {            
       
             
             Object  bean  = null ;
 
              try  {
                    
                    String  className  =  properties .getProperty( name );      //获取 资源配置文件中传入的 键 对应的值
                    System. out .println( "start...................." + className );
                    Class<?>  clazz  = Class. forName ( className );
                    System. out .println( "end...................." );
                    
                     bean  =  clazz .newInstance();    //通过字节码文件将其实例化
             
             }  catch  (Exception  e ) {
                    
                     e .printStackTrace();
             }
             
              /**
              *
              *
              *
              * 若判断 是代理类  ProxyFactoryBean  则  通过代理类去实现
              *
              * 若判断 不是代理类 ,则 直接返回 bean即可
              *
              *
              *
              *
              */
             
              if ( bean   instanceof  ProxyFactoryBean)   ///判断 bean 是否 是代理类实例化的
             {
                    
                    ProxyFactoryBean  proxyFactoryBean  = (ProxyFactoryBean) bean ;   //将 bean实力类 赋给  代理类
                    
                    Object  proxy  = null ;
                    
                     try  {
                            //获取到资源配置文件中 的   adtive  切面 的 值  并 实例化
                           Adtive  adtive  = (Adtive) Class. forName ((String)  properties .get( name + ".adtive" )).newInstance();
                            //获取到资源配置文件中的 target目标类的值 并实例化
                           Object  target  = Class. forName ((String)  properties .get( name + ".target" )).newInstance();
             
                            //将 切面与 目标类 传给 代理类
                            proxyFactoryBean .setAdtive( adtive );
                           
                            proxyFactoryBean .setTarget( target );
                           
                            proxy  =  proxyFactoryBean .getProxy();    //调用 代理方法
                           
                    }  catch  (Exception  e ) {
                           
                            e .printStackTrace();
                    }
                    
                    
             }
             
              return   bean ;
             
             
       }
 
       
       
       
 
}
 
 

1.2 ProxyFactory

package  cn.ittext.day3.aopframework;
import  java.lang.reflect.InvocationHandler;
import  java.lang.reflect.Method;
import  java.lang.reflect.Proxy;
import  cn.ittext.day3.Adtive;
/**
@author   winter
@Date     2018年4月1日下午1:52:50
@tel     1394869214 @qq.com
@version  1.0
@describe 代理类的实例化工厂
*/
//代理类的实例化工厂
public   class  ProxyFactoryBean {
        private  Adtive  adtive  ;
       
        private  Object  target ;
 
        public  Adtive getAdtive() {
              return   adtive ;
       }
        public   void  setAdtive(Adtive  adtive ) {
              this . adtive  =  adtive ;
       }
        public  Object getTarget() {
              return   target ;
       }
        public   void  setTarget(Object  target ) {
              this . target  =  target ;
       }
        public  Object getProxy() {
             
             
             Object  colProxy  =Proxy. newProxyInstance (
                            target .getClass().getClassLoader(),       //动态获取 接口的 加载器
                            target .getClass().getInterfaces(),              //动态的活期 接口
                            new  InvocationHandler() {                //代理类的管理者
                           
                            @Override
                            public  Object invoke(Object  proxy , Method  method , Object[]  args throws  Throwable
                           {
                                  /*
                                  * 在这里边有先后顺序的是 beforeMethod 和 afterMethod方法, invoke 方法永远都是最后执行 的
                                  *
                                  */
                                  adtive .beforeMethod();  
                                 
                                 Object  invoke  =  method .invoke( target args );
                           
                                  adtive .afterMethod();
                                 
                                  return   invoke ;
                           }
                    });
             
             
              return   colProxy ;
             
             
       }
       
}
 
 

1.3 切面接口 及 切面 实现类 

package  cn.ittext.day3;
/**
@author   winter
@Date     2018年3月31日下午11:08:54
@tel     1394869214 @qq.com
@version  1.0
@describe切面接口
*/
public   interface  Adtive
{
        void   beforeMethod();
       
        void  afterMethod();
       
}
 
 


package  cn.ittext.day3;
/**
@author   winter
@Date     2018年3月31日下午11:08:39
@tel     1394869214 @qq.com
@version  1.0
@describe 切面实现类
*/
public   class  Adtives  implements  Adtive{
        @Override
        public   void  beforeMethod()
       {
             
             System. out .println( "start.................." );
       
       }
        @Override
        public   void  afterMethod()
       {
             System. out .println( "end.................." );
       }
       
}
 
 
1.4 config.properties

                                        
# xxx  = cn.ittext.day3.aopframework.ProxyFactoryBean
xxx =  java.util.ArrayList
xxx.adtive =  cn.ittext.day3. Adtives
xxx.target =  java.util.ArrayList
#
# 之前配置文件中遇到的问题 :  = 前后 需要用空格 隔开一下
#  注释掉 第二行,说明传入ArrayList类作为 实例化bean
#  注释掉第三行,说明传入代理类作为实例化bean
#
#

1.5 Test

package  cn.ittext.day3.aopframework;
import  java.io.InputStream;
import  java.util.ArrayList;
import  java.util.Iterator;
/**
@author   winter
@Date     2018年4月1日下午2:10:54
@tel     1394869214 @qq.com
@version  1.0
@describe  类功能描述
*/
public   class  AopFrameworkTest {
       
        public   static   void  main(String[]  args throws  InstantiationException, IllegalAccessException
       {
             
       
              /**
              * 庖丁解牛:
              *
              * 如何自制一个Spring框架  :
              *
              * 1. 需要的类
              *
              * [1] BeanFactory :  用来接收 获取 资源配置文件的内容 ,并 判断是代理类的方式 还是 普通类的方式而 做出相应的反应
              *
              * [2] ProxyFactoryBean :  用来接收 代理类的  目标类和 切面 , 从而实现 代理类的实例化
              *
              *
              *
              *
              */
             
             
              //通过自身类获取一个资源配置文件,将其赋给 输入流
       
             InputStream  ips  = AopFrameworkTest. class .getResourceAsStream( "config.properties" );
             
              //向bean工厂内传入资源配置文件,并获取 实例化bean方法
             Object  bean  = new  BeanFactory( ips ).getBean( "xxx" );
             
              sop ( bean .getClass().getName());
             
              //获取到的实例化bean方法 , 来做个测试 ,我们知道 配置文件中配置的就是 arrayList ,因此 可 转化为  arraylist
             ArrayList<String>  arr  =  (ArrayList<String>)  bean .getClass().newInstance() ;
             
              arr .add( "A" );
              arr .add( "S" );
              arr .add( "D" );
             
              for (Iterator<String>  it  = arr .iterator(); it .hasNext();)
             {
                     sop ( it .next());
                    
             }
 
       }
       
        public   static   void  sop(Object  obj ) {
             System. out .println( obj );
       }
}
 
 

2 ) . 关系图:  


3 ) .  小结 : 

3.1 AOP框架的核心 : 

[1] 代理类的实例化工厂

[2] 普通类的实例化工厂

[3] 测试  :  需要 传入 配置文件 ,获取其 bean的名字  即可 
 
小结 : 若是代理类则 通过 其自定义的 代理方式去实例化,若是普通类 则通过 正常方式实例化



小结 :  

             1.  Aop就是 面向切面编程.所谓的切面 就是 交叉方法, 也就是我们在用代理类实现的过程当中写 通用方法的地方
        
           2.  IOC就是 控制反转,就是将 实例化对象的方式通过反射交由给了配置文件,以此 实现了 控制权的反转

      

       十四. 总结


1 ) . 加载器就是 用来加载类的 一个容器 , 不同的加载器不同的地方在于规定的加载文件的位置的不同,每一个框架也都有属于自己的加载器 ,自定义的加载器还可实现 加密解密 从而 使得代码只能自己观看

2 ) . spring底层所使用的 是  代理机制 +  IO流  + 反射 + 加载器  

所谓的动态代理 就是 通过反射的方式 将 获取的方法与目标类相连接 ,从而实现 代理 ,  框架的底层用的都是反射 ,因为 要动态获取 

代理的最大优势就是 可在 代码的执行前后  过滤自己想过滤的内容

IO流在Spring中用来获取 资源文件并转化成 可通过 键值对获取的 properties

反射在Spring中用来动态的获取对象的字节码以此来实例化对象

加载器在Spring中用来配合代理类的实现 

  
   




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP底层实现原理主要是基于动态代理。Spring AOP通过使用代理模式,在运行时动态地为目标对象生成一个代理对象,然后通过代理对象来完成对目标对象的方法增强。 具体实现步骤如下: 1. 定义切面类:切面类是一个普通的Java类,用于定义切点和增强逻辑。切点是指确定在何处应用增强逻辑的表达式。增强逻辑是指在切点处插入的具体行为,如日志记录、事务管理等。 2. 配置切面:在Spring配置文件中,通过<aop:aspect>标签配置切面类,并使用<aop:pointcut>标签定义切点表达式。 3. 创建代理对象:在Spring启动时,会解析配置文件并扫描所有的Bean对象。当Spring发现某个Bean对象需要进行AOP增强时,会为该对象动态地创建一个代理对象。代理对象可以通过JDK动态代理或者CGLIB动态代理来创建。 4. 方法调用时的增强逻辑:当通过代理对象调用方法时,实际上是调用了代理对象中的方法。在代理对象的方法中,会根据切点表达式判断是否需要插入增强逻辑。如果需要插入增强逻辑,则会在方法的前后或者异常抛出时执行相应的增强操作。 总结起来,Spring AOP底层实现原理是通过动态代理,在运行时为目标对象生成代理对象,并在代理对象中实现对目标对象方法的增强。这个过程是在Spring启动时进行的,通过配置文件中的切面定义和切点表达式,确定增强逻辑的插入位置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值