对java 中动态代理和静态代理的理解
对java 中动态代理和静态代理的理解
代理模式可以有效的将具体实现与调用进行解耦,通过面向接口进行编码完全将具体的实现隐藏在内部。
代理实现的一般模式:定义一个接口,然后创建具体的实现类实现这个接口,创建一个代理类还实现这个接口,具体的实现类需要把接口中定义的方法的业务逻辑实现,而代理类中的方法只要调用实现类中的对应方法即可。之后我们需要使用接口中的某个方法的功能时直接调用代理类的方法就可以了,将具体的实现类隐藏在底层。
静态代理和动态代理的区别:主要是代理类的创建不同。静态代理是我们在编译之前就直接实现与代理类相同的接口,直接在实现的方法中调用实现类的相应方法就可以了。而动态代理不同,我们不知道什么时候创建,创建针对哪个接口,实现类的代理类等。静态代理可以直接编码创建,而动态代理是通过反射机制来抽象出代理类的创建过程。
所谓静态代理就是,在编译的时候就将接口、实现类、代理类都手动完成。
接口:
/**
* 代理类和被代理类公共的接口
* @author TYX
*
*/
public interface Person {
//上交班费
void getMoney();
}
具体实现类:
/**
* 定义一个被代理的类,继承公共接口
* @author TYX
*
*/
public class Student implements Person {
private String name;
public Student(String name) {
super();
this.name = name;
}
@Override
public void getMoney() {
System.out.println("上交班费50元");
}
}
代理类:
/**
* 静态代理在程序运行之前已经编译好了。
* 代理类,类中定义一个被代理类的实体,还有代理的行为
* @author TYX
*
*/
public class StudentProxy implements Person {
//定义一个被代理类的对象
Student student;
//这个构造器传入的是一个接口的对象
public StudentProxy(Person student2) {
//只代理student这个类
if(student2.getClass() == Student.class){
this.student = (Student) student2;
}
}
//代理上交班费
@Override
public void getMoney() {
/*代理类就是在访问实际对象时引入的一定程度的间接性,正是由于这种间接性,可以附加很多种
用途间接性就是指不直接调用对象的方法,那么我们在代理过程中加上一些其他的用途,使用用代理就可以轻松办到 * */
System.out.println("最近这位同学表现很好哦~");//在一个切点之前能执行一些别的操作这就是AOP中的特点。也可以在调用代理类之后进行操作。
student.getMoney();
}
}
测试类:
public class TestStaticProxy {
public static void main(String[] args) {
//定义一个学生对象
Person student = new Student("张三");
//生成代理对象,并将学生对象传给代理对象
Person moniter = new StudentProxy(student);
//班长代理上交班费
moniter.getMoney();
}
}
结果
最近这位同学表现很好哦~
上交班费50元
所谓静态代理就是,在编译的时候就将接口、实现类、代理类都手动完成。
接口:
/**
* 代理类和被代理类公共的接口
* @author TYX
*
*/
public interface Person {
//上交班费
void getMoney();
}
具体实现类:
/**
* 定义一个被代理的类,继承公共接口
* @author TYX
*
*/
public class Student implements Person {
private String name;
public Student(String name) {
super();
this.name = name;
}
@Override
public void getMoney() {
System.out.println("上交班费50元");
}
}
代理类:
/**
* 静态代理在程序运行之前已经编译好了。
* 代理类,类中定义一个被代理类的实体,还有代理的行为
* @author TYX
*
*/
public class StudentProxy implements Person {
//定义一个被代理类的对象
Student student;
//这个构造器传入的是一个接口的对象
public StudentProxy(Person student2) {
//只代理student这个类
if(student2.getClass() == Student.class){
this.student = (Student) student2;
}
}
//代理上交班费
@Override
public void getMoney() {
/*代理类就是在访问实际对象时引入的一定程度的间接性,正是由于这种间接性,可以附加很多种
用途间接性就是指不直接调用对象的方法,那么我们在代理过程中加上一些其他的用途,使用用代理就可以轻松办到 * */
System.out.println("最近这位同学表现很好哦~");//在一个切点之前能执行一些别的操作这就是AOP中的特点。也可以在调用代理类之后进行操作。
student.getMoney();
}
}
测试类:
public class TestStaticProxy {
public static void main(String[] args) {
//定义一个学生对象
Person student = new Student("张三");
//生成代理对象,并将学生对象传给代理对象
Person moniter = new StudentProxy(student);
//班长代理上交班费
moniter.getMoney();
}
}
结果
最近这位同学表现很好哦~
上交班费50元
动态代理:代理类在运行时因需实时创建。
接口:
public interface Person {
//上交班费
void getMoney();
}
具体实现类
/**
* 定义一个被代理的类,继承公共接口
* @author TYX
*
*/
public class Student implements Person {
private String name;
public Student(String name) {
super();
this.name = name;
}
//定义一个方法执行时间的方法
@Override
public void getMoney() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("上交班费50元");
}
}
代理类
/**
* 动态代理实现
* 类中有一个被代理类的实例,所有执行代理对象的方法都会被替换成执行invock方法
* @author TYX
*
*/
public class StudentProxyHandler<T> implements InvocationHandler {
//定义一个被代理类的对象
private T targe;
public StudentProxyHandler(T targe) {
super();
this.targe = targe;
}
/**
* proxy 是被代理对象(实例)
* method 正在执行的方法
* args 调用目标方法时传入的实参
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理执行" + method.getName() + "方法");
MonitorUtil.start();
Object result = method.invoke(targe, args);
MonitorUtil.finish(method.getName());
return result;
}
public Object proxyInstance(){
return Proxy.newProxyInstance(targe.getClass().getClassLoader(), targe.getClass().getInterfaces(), this);
}
}
测试类
/**
* 创建一个动态代理对象的步骤
* 1. 创建一个与代理对象向关联的invocationHandler
InvocationHandler stuHandler = new StudentProxyHandler<Person>(student1);
2. 使用Proxy类的getProxyClass静态方法生成一个动态代理类的stuProxyClass
Class<?> stuProxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), Person.class.getInterfaces());
3. 获得stuProxyClass 中一个带InvocationHandler参数的构造器cnstructor
Constructor<?> constructor = stuProxyClass.getConstructor(InvocationHandler.class);
4. 构造器Constructor来创建一个动态实例
Person stuProxy = (Person) constructor.newInstance(stuHandler);
* @author TYX
*
*/
public class TestDynamicProxy {
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
// Person student = new Student("张三");
//创建一个被代理类的实例对象
Person student1 = new Student1("李四");
//创建一个与代理对象向关联的invocationHandler
InvocationHandler stuHandler = new StudentProxyHandler<Person>(student1);
//创建一个代理对象stuProxy来代理被代理类的实例,代理对象的每个执行方法都会替换执行invocation中的invock方法
Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);
//代理执行上交班费的方法
stuProxy.getMoney();
/*Person student1 = new Student1("李四");
//创建一个与代理对象向关联的invocationHandler
StudentProxyHandler stuHandler = new StudentProxyHandler<Person>(student1);
//创建一个代理对象stuProxy来代理被代理类的实例,代理对象的每个执行方法都会替换执行invocation中的invock方法
Person stuProxy = (Person) stuHandler.proxyInstance();
//代理执行上交班费的方法
stuProxy.getMoney();*/
}
}
结果
代理执行getMoney方法
交作业喽
getMoney方法耗时2000ms
总结:
1.首先要创建接口,jdk代理是基于接口实现的。
2.创建一个有代理对象关联的invocationHandler,重写invocationHandler 接口里的invock()方法
3.通过Proxy.newProxyInstance创建一个代理对象。
4.用代理对象调用方法
接下来看一下cglib动态代理的实现:https://www.cnblogs.com/mr-long/p/5889054.html
jdk动态代理需要实现接口,当需要代理的类没有实现接口时cglib代理是一个很好的选择。但是被代理类中的final方法,无法进行代理,因为子类中无法重写final函数