下载本文章演示案例工程代码
首先,要明确什么是代理。通俗的说,就是日常生活中的中介。比如你要租房子,找了中介,中介负责打理你的一切事务(找房、签约等),这些事务你都不用做,你就负责住房就可以。代理同理,如果你想访问一个目标对象,就得通过代理对象去访问,代理对象会进行一些操作后(验证、打印日志等)才让你访问目标对象,也可以在你访问对象后进行一些代理操作。代理可以实现在保持目标对象代码不变的情况下,对对象访问前后进行一些操作,简而言之,如下图所示,就是对目标对象的访问控制。代理可以分为静态代理和动态代理。
要想采用静态代理方式,需要具备以下条件:
1.目标类具有接口,并实现了其接口。
2.代理类也得实现目标类的接口,并有一个属性是目标类接口。
3.代理类的得有一个无参构造方法和一个构造方法,参数为目标类接口类型,用于接收目标对象赋值给代理类的目标类接口属性。
4.代理类必须实现接口的所有方法,并在在方法中访问目标类对象的方法,在访问之前和之后都可以进行一些代理操作。UML如下图所示:
package testspringAOP.proxy;
/**
* @author CenterLogo
*create date :2019年4月28日 下午6:36:14
*/
public interface MassegeService {
public void sendMessage1();
public void sendMessage2();
public void sendMessage3();
}
package testspringAOP.proxy;
/**
* @author CenterLogo
*create date :2019年4月28日 下午6:39:23
*/
public class MassegeServiceImpl implements MassegeService {
/**
* 业务逻辑实现类(被代理类)
*/
public MassegeServiceImpl() {
// TODO Auto-generated constructor stub
}
public void sendMessage1() {
// TODO Auto-generated method stub
System.out.println("hello maven");
}
public void sendMessage2() {
// TODO Auto-generated method stub
System.out.println("hello Spring");
}
public void sendMessage3() {
// TODO Auto-generated method stub
System.out.println("hello mybatis");
}
}
package testspringAOP.proxy;
/**静态代理类
* @author CenterLogo
*create date :2019年4月28日 下午6:52:44
*/
public class staticProxy implements MassegeService {
MassegeService ms;//引入接口
protected staticProxy() {//将无参构造修饰为受保护的,一般项目分包处理,代理。同子类才能调用无参。
}
public staticProxy(MassegeService ms) {//有参构造,传入被代理实例(目标对象),使用代理。
this.ms=ms;
}
public void validatorInfo(){ //服务方法,业务为逻辑处理
System.out.println("完成数据验证操作。");
}
public void sendMessage1() {
this.validatorInfo();
ms.sendMessage1();
}
public void sendMessage2() {
this.validatorInfo();
ms.sendMessage2();
}
public void sendMessage3() {
this.validatorInfo();
ms.sendMessage3();
}
}
package testspringAOP.proxy;
/**
* @author CenterLogo
*create date :2019年4月28日 下午6:48:58
*/
public class ProxyTest {
public ProxyTest() {
// TODO Auto-generated constructor stub
}
public void testStatic(){
//通过传目标对象实例获取代理类,通过代理类对象访问目标对象实例方法。
MassegeService ms =new staticProxy(new MassegeServiceImpl());
ms.sendMessage1();
ms.sendMessage2();
ms.sendMessage3();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ProxyTest pt=new ProxyTest();
pt.testStatic();
}
}
测试成功结果为:
完成数据验证操作。
hello maven
完成数据验证操作。
hello Spring
完成数据验证操作。
hello mybatis
静态代理类需要实现目标类(被代理类)的接口,并实现其方法,造成了代码的大量冗余。
静态代理只能对某个固定接口的实现类进行代理服务,其灵活性不强。故一般大项目不会选择静态代理。
动态代理能够实现代理类无需和被代理类直接关联,但是动态代理类必须实现Invocation接口,并且实现invoke() 方法,在invoke()方法中需要完成两件事情:一是添加服务,二是调用业务逻辑方法。代理服务就是在代理类中的invoke中执行的。我们可以通过反射机制获取目标对象的加载类、接口,还有实现了Invocation接口的代理类传到Proxy.newProxyInstance(被代理类,被代理类接口,代理类)方法中获取到代理类的对象实例。
package testspringAOP.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理类
* @author CenterLogo
*create date :2019年4月28日 下午7:32:18
*/
public class DynamicProxy implements InvocationHandler {
private Object obj;
public DynamicProxy() { //无参构造
}
public Object bin(Object obj){//参数传入被代理对象,返回代理对象实例
this.obj=obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);//代理中的invoke()方法在这Proxy.newProxyInstance()中执行
}
public void validatorInfo(){ //服务方法,业务为逻辑处理
System.out.println("完成数据验证操作。");
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj=null;
this.validatorInfo();
obj=method.invoke(this.obj, args);
return obj;
}
}
package testspringAOP.proxy;
/**
* @author CenterLogo
*create date :2019年4月28日 下午6:48:58
*/
public class ProxyTest {
public ProxyTest() {
// TODO Auto-generated constructor stub
}
public void testDynamic(){
MassegeService ms =(MassegeService) new DynamicProxy().bin(new MassegeServiceImpl());
ms.sendMessage1();
ms.sendMessage2();
ms.sendMessage3();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ProxyTest pt=new ProxyTest();
pt.testDynamic();
}
}
测试成功结果为:
完成数据验证操作。
hello maven
完成数据验证操作。
hello Spring
完成数据验证操作。
hello mybatis
一般大型项目都选择采用动态代理方式,如SpringAOP就采用了动态代理,有jdk动态代理和cglib动态代理。欲了解SpringAOP动态代理,请看《AOP动态代理声明式的3种配置方式过程与区别》。