回顾Java反射知识
因为动态代理需要用到,所以我们要先学习Java的反射知识。
Java反射中有Method类
Method类,表示方法类中的方法,通过Method可以执行某个类中的某个方法
回顾反射知识咋用
1 先创建一个接口
package com.test;
public interface HelloService {
// 根据name打招呼
public void sayHello(String name);
}
2 创建一个类实现这个接口
package com.test;
// HelloService接口的实现类
public class HelloServiceImpl implements HelloService {
@Override
public void sayHello(String name) {
System.out.println("您好"+name);
}
}
3 测试,执行HelloServiceImpl这个类里面的方法
package com.test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
// 测试
public class TestHelloService {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 正常的通过对象调用sayHello方法
创建这个类的对象后执行这个方法,是最普遍的方法
HelloService helloService = new HelloServiceImpl();
System.out.println("通过对象调用sayHello方法");
helloService.sayHello("张三");
通过反射,咋执行这个方法
// 通过反射机制执行sayHello方法,核心Method(类中的方法)
// 创建需要调用sayHello的对象
HelloService Service = new HelloServiceImpl();
// 获取sayHello名称对应的Method类对象
// method代表的是sayHello这个方法
/* 参数: 1.需要执行的方法名 2.参数的类型 */
Method method = HelloService.class.getMethod("sayHello", String.class);
// 通过Method可以执行sayHello方法的调用
/* invoke是Method类中的一个方法,表示执行方法的调用 参数: 1.Object:表示对象,就是要执行这个对象的sayHello方法 2.Object...args:方法执行时的参数值 返回值:Object,表示返回执行后的返回值,sayHello返回是void */
// 表示执行Service对象的sayHello返回参数是李四
System.out.println("通过反射调用sayHello方法");
Object object = method.invoke(Service,"李四");
}
}
动态代理
什么叫动态代理
不用自己手动的去创建代理类。
我们自己的一个类,可以创建很多的对象,现在想要在这么多对象上,都要创建代理类。意思是每一个对象都需要创建代理类,我们就可以动态的实现。
jdk动态代理,实际类和代理类一定要实现同一个接口,这个必须记住
jdk的动态代理:
jdk动态代理使用到
反射包java.lang.reflect,里面包含3个类InvocationHandler、Method、Proxy
InvocationHandler接口(调用处理器):Invoke()方法,(需要执行的功能,我的理解:原来的方法和扩展的方法)
实现步骤
1 写一个接口,这个接口是实际类和代理类都需要实现的。jdk动态代理就是实际类和代理类都要实现同一个接口,重写里面的 方法,这个是必须的
我们先写一个接口
package com.service;
// 目标类实现的方法
public interface UsbSell {
public float sell(int amount);
}
2 写一个实际类,实现这个接口,重写里面的方法
这个类就是实际类,我们要对这个里面的方法功能实现扩展。
package com.factory;
import com.service.UsbSell;
// 目标类
public class UsbKingFactory implements UsbSell {
// 目标方法
@Override
public float sell(int amount) {
System.out.println("执行目标类方法sell");
return 85.0f;
}
}
3 创建InvocationHandler接口的实现类
这个是必须的,相当于这个类里面就是写功能扩展的方法。相当于aop,
里面不仅有原来的方法,还有功能扩展的方法
package com.handler;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
// 必须实现InvocationHandler接口,完成代理功能(1.调用目标方法,2.功能增强)
// 负责执行目标类的方法
// 我的理解:只是执行了目标类的方法和代理类的功能增强,返回目标类方法的返回值给InvocationHandler对象
public class MySellHandle implements InvocationHandler {
private Object target = null;
// 动态代理:目标对象是活动的,不是固定的,需要传进来
// 传入是哪个对象,就给哪个对象创建代理
public MySellHandle(Object target){
// 给目标对象赋值
this.target = target;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
Object res = null;
//在代理真实对象前我们可以添加一些自己的操作
System.out.println("在调用之前,我要干点啥呢?");
System.out.println("Method:" + method);
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
Object returnValue = method.invoke(target , objects);
//在代理真实对象后我们也可以添加一些自己的操作
System.out.println("在调用之后,我要干点啥呢?");
return returnValue;
}
}
4 创建测试类,使用Proxy类的静态方法newProxyInstance,创建代理对象
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/** * 动态代理演示 */
public class DynamicProxyDemonstration
{
public static void main(String[] args)
{
//代理的真实对象
Subject realSubject = new RealSubject();
/** * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发 * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用. * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法 */
InvocationHandler handler = new InvocationHandlerImpl(realSubject);
ClassLoader loader = realSubject.getClass().getClassLoader();
Class[] interfaces = realSubject.getClass().getInterfaces();
/** * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 */
Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
System.out.println("动态代理对象的类型:"+subject.getClass().getName());
String hello = subject.SayHello("ttt");
System.out.println(hello);
// String goodbye = subject.SayGoodBye();
// System.out.println(goodbye);
}
}
注意
注意的是在使用jdk动态代理时目标类一个要实现实现功能接口。
动态代理相当于就是实现 功能的扩展