代理的概念:
1、代理对象存在的价值主要是用于拦截真实业务对象的访问。
2、代理对象应该具有和目标对象(真实业务对象)相同的方法。
静态代理:
1、需要定义接口或者父类。
2、被代理的对象与代理对象一起实现相同的接口或者继承相同的父类。
静态代理小案例:
public class Test {
public static void main(String[] args) {
Human p=new Human();
Proxy proxy=new Proxy(p);
proxy.sing();
}
}
/*
* 接口
*/
interface Sing{
void sing();//唱歌
}
class Human implements Sing{
@Override
public void sing() {
System.out.println("唱歌");
}
}
class Proxy implements Sing{
//接收一个需要代理的对象
Human p=new Human();//p为一个歌手
public Proxy(Human p) {
super();
this.p = p;
}
@Override
public void sing() {
p.sing();
}
}
静态代理特点分析:
静态代理通常只代理一个类,静态代理要实现知道要代理什么。
因为代理对象需要与目标对象实现一样的接口,所以会有很多的代理类,一旦接口增加方法,那么目标类与代理类都要进行修改,不利于维护。
动态代理:
java.lang.reflect.Proxy类的介绍:
java在jdk1.5之后提供了一个java.lang.reflect.Proxy类的newProxyInxtance()方法创建一个代理对象。
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
注:newProxyInstance方法返回一个代理对象,此方法有三个参数,ClassLoader loader用于指明生成代理对象使用哪个类加载器,Class>[] interfaces用于指明生成哪个对象的代理对象,通过接口指定,InvocationHandler h用来指明产生的这个代理对象要做什么事情。所以我们只需要调用newProxyInstance方法就可以得到某个对象的代理对象了。
模拟动态代理小案例:
在java中规定,要想生成一个对象的代理对象,那么这个对象必须要有一个接口,这个接口定义这个对象所具有的行为。
接口:
public interface Person {
String sing(String name);
String dance(String name);
}
歌手:
public class Singer implements Person {
@Override
public String sing(String name) {
System.out.println("歌手唱"+name+"歌!!");
return "演出结束,谢谢大家";
}
@Override
public String dance(String name) {
System.out.println("歌手跳"+name+"舞蹈!!");
return "演出结束,谢谢大家";
}
}
生成代理类:
public class SingProxy {
//代理类需要代理的目标
private Person s=new Singer();
public Person getProxy(){
//SingProxy.class.getClassLoader():指明生成代理对象使用哪个类加载器
//s.getClass().getInterfaces():指明生成哪个对象的代理
//new InvocationHandler指明代理需要做的事情
return (Person) Proxy.newProxyInstance(SingProxy.class.getClassLoader(),s.getClass().getInterfaces() , new InvocationHandler(){
//使用到反射的知识
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(s, args);
}
});
}
}
测试类:
public class Test {
public static void main(String[] args) {
SingProxy proxy=new SingProxy();
//获取代理对象
Person p=proxy.getProxy();
//调用代理的sing方法
String sing =p.sing("冰雨");
System.out.println(sing);
//调用代理的sing方法
String dance=p.dance("巴拉巴拉");
System.out.println(dance);
}
}
面试题:写一个ArrayList的动态代理类
public class Test {
//定义一个需要代理的对象
static List list=new ArrayList<>();
//list.getClass().getClassLoader():指明生成代理对象使用哪个类加载器
//list.getClass().getInterfaces():指明生成哪个对象的代理,接口
@SuppressWarnings("unchecked")
static List listProxy=(List) Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler(){
{
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(list, args);
return list;
}
});
public static void main(String[] args) {
listProxy.add("hello");
System.out.println(list);
}
}
动静态代理的区别,什么场景下使用?
1、静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类
2、静态代理事先知道代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才会知道。
3、动态代理是实现jdk中的InvocationHandler接口的invoke方法,但注意的是代理的是接口,也就是你的
业务类必须要实现的接口,通过Proxy里的newProxyInstance得到代理对象。
CDLIB动态代理:
动态代理CDLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行时,动态的修改字节码达到修改类的目的。
上面的静态代理与动态代理模式都要求目标对象实现了一个接口。CGLIB代理,也叫子类代理,代理效率高于jdk,它是在内存中构建一个对象从而实现对目标对象功能的扩展。
cglib动态代理有如下特点:
1. jdk的动态代理有一个限制,就是使用动态代理的对象必须实现一个或者多个接口,如果没有实现接口的类需要代理可以使用chlib实现。
2. cglib是一个强大的高性能的代码包,它可以在运行期间扩展java类与实现java接口,它广泛的被许多的AOP的框架使用。
3. cglib的底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类,不鼓励直接使用ASM,因为它要求你 必须对JVM内部结构,包括class文件的格式和指令集都很熟悉。
4. 需要引入cglib的jar文件,但是Spring的核心包中已经包含Cglib功能,所以直接引入pring-core-3.3.5,jar即可。
5. 引入功能包之后就可以在内存中动态的构建子类。
6. 代理的类不能为final,否则报错。
7. 目标对象的方法如果为final/static,那么就不会执行目标对象额外的业务方法。
cglib动态代理小案例:
public class Test {
public static void main(String[] args) {
Singer1 singer=new Singer1();
ProxyFactory pf=new ProxyFactory(singer);
Singer1 singer1=(Singer1) pf.getProxy();
singer1.sing();
}
}
class Singer1{
void sing(){
System.out.println("歌唱");
}
}
class ProxyFactory implements MethodInterceptor{
//维护目标对象
private Object obj=new Object();
public ProxyFactory(Object target) {
super();
this.obj = target;
}
//提供方法获取代理
public Object getProxy(){
//工具类
Enhancer en=new Enhancer();
//设置父类
en.setSuperclass(obj.getClass());
//设置回调
en.setCallback(this);
//创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
return method.invoke(obj, args);
}
}
注:AOP编程就是基于动态代理实现的,比如著名的Spring框架,Hibernate框架都是动态代理的例子。
参考文章:https://blog.csdn.net/yangsnow_rain_wind/article/details/79291256