代理(AOP)
1、静态代理:
使用静态代理必须实现的功能:1、目标类中方法的调用
2、功能的增强
1.1、静态代理的代码演示:
- 创建一个接口
//创建手机厂商
public interface TelePhone {
public float shell(int number);
}
- 创建一个对应的实现
//小米工厂
public class XiaoMiPhone implements TelePhone {
@Override
public float shell(int number) {
float num = number * 50;
return num;
}
}
- 使用代理:
public class Taobao implements TelePhone {
private XiaoMiPhone xiaomi = new XiaoMiPhone();
@Override
public float shell(int number) {
float price = xiaomi.shell(number); //
price = price + 20*number; //增加20 功能增强
return price;
}
}
- Main方法
public class PeopleMain{
public static void main(String[] args) {
Taobao taobao = new Taobao();
float price = taobao.shell(1);
System.out.println(price);
}
}
静态代理就不多说了
2.动态代理:
在静态代理中目标类很多时候,可以使用动态代理,避免静态代理的缺点
动态代理中目标类即使很多,1)代理数量可以很少,2)但你修改了接口中的方法时不会影响到代理类
动态代理: 在程序执行过程中,使用jdk的反射机制,创建代理对象,并且动态的指定要代理的目标 换句话说: 动态代理是一种创建java对象的能力,让你不用创建Taobao类,就能代理对象
在Java中,想要代理对象:
1、创建类文件,java文件编译为class
2、使用构造方法,创建类的对象
动态代理的实现:
1.jdk动态代理:使用java反射包中的类和接口实现动态代理的功能
反射包 java.lang.reflect ,里面有三个类: InvocationHandler,Method,Proxy
2.cglib动态代理:cglib是第三方工具库,创建代理对象。cglib的原理是基础,cglib通过继承目标类,创建它的子类,在子类中重写父类中同名的方法,实现功能的修改
因为cglib是继承,重写方法,所以要求目标不能是final修饰的,方法也不能是final修饰的,cglib的要求目标类比较宽松,只要能继承就可以了。cglib在很多的框架中使用,例如;mybatis,spring框架中都有使用
Cglib的效率高于jdk
2.1、JDK动态代理
2.1.1、反射:
-
Method类,表示方法。类中的方法。通过method可以执行某个方法
public class HelloReflect { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Hello hello = new SayHello(); //2个参数 /* * 第一个参数对应方法名称 * 第二参数对于的方法的参数 * */ Method method = hello.getClass().getMethod("sayHello", String.class); //2个参数: // 1、Object obj :表示对象,需要执行的这个对象方法 // 2. Object... args : 方法执行时的参数 // 返回值: Objec : 方法执行后的放回只 Object object= method.invoke(hello, "张三"); } }
我们发现使用该方法之后我们不需要再去改变其他只需要把对应的对象传入进去就可以了
2.1.2、jdk动态代理的实现
反射包 java.lang.reflect , 里面的三个类:InvocationHandler、Method、Proxy.
1) InvocationHandler接口 (调用处理器):就一个方法invoke( )
invoke( ):表示代理对象要执行的功能代码。你代理类要完成的功能写在invoke( )方法中。
代理类完成的功能:
- 调用目标方法,执行目标方法的功能
- 功能增强,在目标方法调用时,增加功能
方法原型:
public Object invoke(Object proxy, Method method, Object[] args)
/*
Object proxy: jdk创建的代理对象,无需赋值
Method method: 目标类中的方法,jdk提供method的对象
Object[] args : 目标类中的参数,jdk提供的。
*/
怎么用:
1、创建类实现接口InvocationHandler
2、重写invoke( )方法,把原来静态代理中代理要完成的功能,写在这里
**2)Method类;**表示方法的,确切的说就是目标类中的方法。
作用:通过Method可以执行某个目标类的方法,Method.invoke();
method.invoke(目标对象,方法的参数)
Object ret = method.invoke(service,"小明’’);
说明:method.invoke( ) 就是用来执行目标方法的,等同于静态代理中向厂家发送订单,告诉厂家,买了手机,厂家发货
**3)Proxy类:**核心的对象,创建代理对象。之前是使用new 类的构造方法,现在我们使用Proxy类的方法,代替new的使用。
方法: 静态方法 newProxyInstance()
作用是: 创建代理对象,等同于静态代理中的Taobao taobao = new Taobao();
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
参数;
1.ClassLoader loader是类加载器,负责向内存中加载对象的,使用反射获取对象的ClassLoader
2. Class<?>[] interfaces:
3.InvocationHandler h: 我们自己写的,代理类要完成的功能
返回值: 就是代理对象
3.实习动态代理的步骤:
- 1.创建接口,定义目标类要完成的功能
- 2.创建目标类实现接口
- 3.创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
- 1.调用目标方法
- 2.增强功能
- 4.使用Proxy类的静态方法,创建代理对象。并把返回值转换为接口类型。
代码实现:
//创建手机厂商
public interface TelePhone {
public float shell(int number);
}
public class XiaoMiPhone implements TelePhone { @Override public float shell(int number) { float price = 2000 * number; return price; }}
public class MyPhoneHandler implements InvocationHandler{
private Object target = null;
public MyPhoneHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1.调用目标方法
Object res = null;
res = method.invoke(target, args);
//2.功能增强
if (res!=null){
float price = (float) res;
price = price + 1000;
res = price;
}
return res;
}
}
public class MainShop {
public static void main(String[] args) {
//1.创建目标对象
TelePhone telePhone = new XiaoMiPhone();
//2.创建代理对象
InvocationHandler handler = new MyPhoneHandler(telePhone);
//3. 目标对象
TelePhone phone = (TelePhone) Proxy.newProxyInstance(telePhone.getClass().getClassLoader(),
telePhone.getClass().getInterfaces(),
handler);
//4.通过代理实现:
float shell = phone.shell(1);
System.out.println(shell);
}
}