代理提供了对目标对象的另外的访问方式,即通过代理对象访问目标对象,这样可以扩展目标对象的功能。
java有三种代理模式,分别为静态代理、动态代理、cglib代理
代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象
1、静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类
接口
public interface IUserDao {
public void add();
}
目标对象
public class UserDao implements IUserDao {
@Override
public void add() {
System.out.println("添加方法");
}}
代理对象
public class UserProxy implements IUserDao{
private IUserDao userDao;
public UserProxy(IUserDao userDao) {
super();
this.userDao = userDao;
}@Override
public void add() {
System.out.println("开始事务");
userDao.add();//执行目标对象的方法
System.out.println("提交事务");
}}
测试类
public static void main(String[] args) {
User user = new User();
//目标对象
UserDao userDao = new UserDao();
//把目标对象传给代理对象
UserProxy proxy = new UserProxy(userDao);
//执行的是代理的方法
proxy.add();
}
静态代理优缺点:
优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展.
缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护
要克服静态代理的缺点就需要用到动态代理
2、动态代理
接口和实现类同上静态代理
动态代理需要增加一个代理工厂ProxyFactory
public class ProxyFactory {
private Object target;public ProxyFactory(Object target) {
super();
this.target = target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//可以扩展方法
System.out.println("开始事务");
//执行目标对象方法
Object invoke = method.invoke(target, args);
System.out.println("提交事务");
return invoke;
}
});
}
}
测试类
public static void main(String[] args) {
UserDao userDao = new UserDao();
//给目标对象生成代理对象,注意此处用的是接口而不是实现类,否则会报转换错误
IUserDao proxy =(IUserDao) new ProxyFactory(userDao).getProxyInstance();
User user = new User();
//代理对象执行方法
proxy.add();
}
动态代理中,代理类并不是在Java代码中实现,而是在运行时期生成,相比静态代理,动态代理可以很方便的对委托类的方法进行统一处理,如添加方法调用次数、添加日志功能等等
3、cglib代理
cglib代理也叫子类代理,静态代理和动态代理都需要目标对象实现一个接口,但是实际情况可能是目标函数没有实现接口,此时就可以用cglib代理,它可以在内存中构建一个子类对象来对目标对象的函数来进行扩展
目标对象
public class CglibDao {
public void save() {
System.out.println("执行保存方法");
}
}
创建一个代理工厂,需要引入一个cglib的依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.6</version>
</dependency>
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;public class ProxyFactory2 implements MethodInterceptor{
private Object target;
public ProxyFactory2(Object target) {
super();
this.target = target;
}
public Object getProxyInstance(){
//工具类
Enhancer en = new Enhancer();
//设置父类
en.setSuperclass(target.getClass());
//设置回调函数
en.setCallback(this);
//创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
System.out.println("开始事务");
//执行目标类方法,此处的的invoke的第一个参数为target而不是代理对象obj,否则会不断递归调用intercept方法而导致内存溢出
Object invoke = method.invoke(target, arg2);
System.out.println("提交事务");
return invoke;
}
}
测试类
public static void main(String[] args) {
CglibDao cglibDao = new CglibDao();
//给目标对象生成代理对象
CglibDao proxy =(CglibDao) new ProxyFactory2(cglibDao).getProxyInstance();
//代理对象执行方法
proxy.save();
}
cglib也有局限,它也跳不出jdk的继承机制,对final类无能为力