(十九)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 ) .  类加载器图解 :
《(十九)Core Java 加载器及Spring底层AOP原理实现 (117)》

小结 :  


         
 
 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) 优势 : 灵活性,已修改,可扩展
《(十九)Core Java 加载器及Spring底层AOP原理实现 (117)》



 


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

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



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




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 ) . 关系图:  


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

3 ) .  小结 : 

3.1 AOP框架的核心 : 


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


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


[3] 测试  :  需要 传入 配置文件 ,获取其 bean的名字  即可 

 

小结 : 若是代理类则 通过 其自定义的 代理方式去实例化,若是普通类 则通过 正常方式实例化




小结 :  


         
 
 1.  Aop就是 面向切面编程.所谓的切面 就是 交叉方法, 也就是我们在用代理类实现的过程当中写 通用方法的地方

        

           2.  IOC就是 控制反转,就是将 实例化对象的方式通过反射交由给了配置文件,以此 实现了 控制权的反转


      

 
  
  十四. 总结

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


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

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


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


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


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


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


  

   

    原文作者:AOP
    原文地址: https://blog.csdn.net/modaiairen524/article/details/79781458
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞