关于动态代理的操作
一、关于动态代理。
1.动态代理:只学一个方法 方法的作用:在运行时,动态创建一组指定的接口的实现类对象!(在运行时,创建实现了指定的一组接口的对象)
2.动态代理的方法:Object proxyObject = Proxy.newProxyInstance(ClassLoader classLoader, Class[] interfaces, InvocationHandler h);
方法作用:动态创建实现了interfaces数组中所有指定接口的实现类对象!
参数:
① ClassLoader:类加载器!
* 它是用来加载器的,把.class文件加载到内存,形成Class对象!
②Class[] interfaces:指定要实现的接口们
③InvocationHandler:代理对象的所有方法(个别不执行,getClass())都会调用InvocationHandler的invoke()方法。
3.动态代理作用:最终是学习AOP(面向切面编程,这个会在spring里面详细介绍),它与装饰者模式有点相似,它比装饰者模式还要灵活!
4.详细介绍InvocationHandler:
InvocationHandler有一个抽象方法为invoke
public Object invoke(Object proxy, Method method, Object[] args);
这个invoke()方法在什么时候被调用!
①. 在代理对象被创建时?错误的!
②. 在调用代理对象所实现接口中的方法时?正确的!
* Object proxy:当前对象,即代理对象!在调用谁的方法!
* Method method:当前被调用的方法(目标方法)
* Object[] args:实参!
关于动态代理的对象调用接口中的有参数方法时在inovke方法中有个怎么样的对应方式
测试的代码如下:
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 5 import org.junit.Test; 6 7 public class Demo01 { 8 9 @Test 10 public void fun01(){ 11 12 ClassLoader classLoader =this.getClass().getClassLoader(); 13 InvocationHandler invocationHandler =new InvocationHandler() { 14 15 @Override 16 public Object invoke(Object proxy, Method method, Object[] args) 17 throws Throwable { 18 System.out.println("动态代理被调用了"); 19 return "xxx"; 20 } 21 }; 22 23 Object proxyobject = Proxy.newProxyInstance(classLoader, new Class[]{A.class,B.class},invocationHandler ); 24 A a = (A) proxyobject; 25 B b = (B) proxyobject; 26 a.a(); 27 b.b(); 28 proxyobject.toString(); 29 proxyobject.getClass();//这个方法不会调用invoke为啥,点进去看看Object,发现getClass()方法前面有native修饰表示这个方法为本地方法 30 //带有native的都是为本地方法 31 //proxyobject.equals(null); 32 Object result=a.aaa("hello", 1000); 33 System.out.println(result);//null xxx 34 } 35 } 36 interface A{ 37 public void a(); 38 public Object aaa (String str,int i); 39 } 40 interface B{ 41 public void b(); 42 }
根据上面的应用我们来写一个小例子:在一个Waiter类的serve方法的前后加上"你好"、"再见"
Waiter接口代码如下:
package cn.itcast.demo.proxy2;
public interface Waiter {
public void serve();
}
Waiter实现类ManWaiter代码如下:
package cn.itcast.demo.proxy2;
public class ManWaiter implements Waiter{
@Override
public void serve() {
System.out.println("服务中...");
}
}
操作动态代理的测试类代码如下:
package cn.itcast.demo.proxy2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.junit.Test;
/**
* 我们必须要掌握这个案例的东西
* @author 希
*
*/
public class Demo01 {
@Test
public void fun01(){
Waiter waiter =new ManWaiter();
//为了得到代理对象首先准备三个参数
ClassLoader classLoader =this.getClass().getClassLoader();//本类的类加载器
Class[] interfaces = {Waiter.class};//代理的对象
InvocationHandler invocationHandler =new ManWaiterHandler( waiter);
Waiter waiterProxy =(Waiter) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
waiterProxy.serve();//代理对象调用增强后的内容
}
}
class ManWaiterHandler implements InvocationHandler{
private Waiter waiter ;
public ManWaiterHandler(Waiter waiter){//创建一个有参构造让别人提供目标对象
this.waiter=waiter;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("您好");
this.waiter.serve();
System.out.println("再见!");
return null;
}
}
上面的例子中是在invoke方法中添加了两条打印语句对目标方法进行了增强,但是这个样是把目标对象和增强的内容写死了我们不能硬编码
所以根据有上面的例子我们进行修改:
关于目标对象可以不用修改和上面一样
将增强的内容用接口表示出来当要获取代理对象时向里面加入这个接口的实例即可:
1 public interface AfterAdvice { 2 public void after(); 3 4 }
1 public interface BeforeAdvice { 2 public void before(); 3 }
然后我们创建一个得到代理对象的工厂:
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 5 6 7 /** 8 * 1.给定代理工厂 9 * 2.给定工厂设置三样东西: 10 * *目标对象setTargetObject(代理的对象的实例) 11 * *前置增强setBeforeAdivce(该接口的实现) 12 * *后置增强setAfterAdivce(该接口的实现) 13 * 3.调用createProxyObject()//得到最后的代理对象 14 * *执行代理对象方法时 15 * 》执行BeforeAdivce的before()方法具体的实现内容由该接口的实现决定 16 * >目标对象的目标方法 17 * 》执行AfterAdivce的before()方法具体的实现内容由该接口的实现决定 18 */ 19 public class ProxyFactory { 20 private Object tagertObject; 21 private BeforeAdvice beforeAdvice; 22 private AfterAdvice afterAdvice; 23 24 public Object crateProxyObject(){ 25 //准备获得代理的三个参数 26 ClassLoader classLoader =this.getClass().getClassLoader(); 27 Class[] interfaces= tagertObject.getClass().getInterfaces(); 28 InvocationHandler invocationHandler =new InvocationHandler() { 29 30 @Override 31 public Object invoke(Object proxy, Method method, Object[] args) 32 throws Throwable { 33 //在这里填写代理内容 34 //执行前置增强 35 if(beforeAdvice!=null){ 36 beforeAdvice.before(); 37 } 38 Object result=method.invoke(tagertObject, args); 39 //执行后置增强 40 if(beforeAdvice!=null){ 41 afterAdvice.after(); 42 } 43 return result; 44 } 45 }; 46 Object proxyObject = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); 47 48 return proxyObject; 49 50 } 51 52 53 54 55 56 public Object getTagertObject() { 57 return tagertObject; 58 } 59 public void setTagertObject(Object tagertObject) { 60 this.tagertObject = tagertObject; 61 } 62 public BeforeAdvice getBeforeAdvice() { 63 return beforeAdvice; 64 } 65 public void setBeforeAdvice(BeforeAdvice beforeAdvice) { 66 this.beforeAdvice = beforeAdvice; 67 } 68 public AfterAdvice getAfterAdvice() { 69 return afterAdvice; 70 } 71 public void setAfterAdvice(AfterAdvice afterAdvice) { 72 this.afterAdvice = afterAdvice; 73 } 74 75 }
最后的测试类,来测试代理工厂是否可以得到代理对象并调用代理对象的方法:
我们需要向工厂传递:目标对象,前后置增强接口的实现
最后直接将代理对象强转为目标对象类型这样调用目标对象的方法时都会先调用invoke方法
1 import org.junit.Test; 2 3 4 /** 5 * 使用动态代理 6 * @author 希 7 * 8 */ 9 public class Demo01 { 10 11 @Test 12 public void fun01(){ 13 //第一步得到代理工厂的对象来设置目标对象和前置增强后置增强 14 ProxyFactory factory =new ProxyFactory();//创建工厂 15 factory.setBeforeAdvice(new BeforeAdvice() {//设置前置增强 16 17 @Override 18 public void before() { 19 System.out.println("您好!"); 20 21 } 22 }); 23 24 25 factory.setAfterAdvice(new AfterAdvice() { //设置后置增强 26 @Override 27 public void after() { 28 System.out.println("再见!!"); 29 30 } 31 }); 32 33 factory.setTagertObject(new ManWaiter());//给定目标对象 34 Waiter waiter=(Waiter) factory.crateProxyObject(); 35 waiter.serve(); 36 waiter.pay(); 37 } 38 }
我们进行这样的修改后可以发现目标对象和增强的内容都可以替换,目标的装配工作是我们自己手打的,后期会由配置文件来做装配代理对象所需要的东西的工作
动态代理的主要结构如图所示:
目标对象:被增强的对象
代理对象:需要目标对象,然后在目标对象上添加了增强后的对象!
目标方法:增强的内容
代理对象 = 目标对象 + 增强
5.关于类加载器的简单介绍: