java动态代理
代理模式
- 代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式
- 举例说明:黄牛买票
- 用户只关心接口功能,而不在乎谁提供了功能
- 接口真正实现者具体的实现类,但是它不与用户直接接触,而是通过代理。
- 代理由于它实现了被代理的接口,所以它能够直接与用户接触。
- 用户调用代理的时候,代理内部调用了真实的实现类。所以,代理是中介者,它可以增强真实实现类操作。
静态代理
-
需要代理对象和目标对象实现一样的接口
-
优点:可以在不修改目标对象的前提下扩展目标对象的功能。
-
缺点:
- 冗余。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。
- 不易维护。一旦接口增加方法,目标对象与代理对象都要进行修改。
//接口 :通用的接口是代理模式实现的基础
public interface IUserDao {
void save();
}
//真正地实现类
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("保存数据");
}
}
//静态代理类 需要和代理对象实现同一接口
public class UserDaoProxy implements IUserDao {
private IUserDao target;
public UserDaoProxy(IUserDao target){
this.target =target;
}
@Override
public void save() {
System.out.println("开启事务"); //可以自由扩展功能
target.save();
System.out.println("提交事务");//可以自由扩展功能
}
public static void main(String[] args) {
IUserDao userDao =new UserDao();
UserDaoProxy userDapProxy =new UserDaoProxy(userDao);
userDapProxy.save();
}
}
动态代理
-
动态代理之所以叫动态就是因为它是在运行时动态生成的,编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
-
特点:不需要实现接口,但是目标对象必须实现接口,否则不能使用动态代理
java动态代理中两个重要的接口和类,这一个类和接口是实现我们动态代理所必须用到的
- InvocationHandler(Interface):每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy: 指我们所代理的真实对象
method: 指我们所要调用真实对象的某个方法的Method对象
args: 指调用真实对象某个方法时接受的参数
- Proxy(Class):用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是将要给需要代理的对象提供一组什么接口,如果提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h: 一个InvocationHandler对象,表示的是当这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
- 举例
//动态代理
public class UserDaoProxy implements InvocationHandler{
private Object target;
public ProxyFactory(Object target){
this.target=target;
}
//为目标对象生成代理对象
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开启事务");//可以自由扩展功能
// 执行目标对象方法
method.invoke(target, args);
System.out.println("提交事务");//可以自由扩展功能
return null;
}
//测试方法
public static void main(String[] args) {
IUserDao userDao =new UserDao();
System.out.println("目标对象信息 "+userDao.getClass());
InvocationHandler handler =new UserDaoProxy(userDao);
/*
* 通过Proxy.newProxyInstance()方法来创建代理对象
* handler.getClass().getClassLoader() ,加载代理对象
* userDao.getClass().getInterfaces(),为代理对象提供的接口是真实对象要实行的接口,表示要代理的是真实对象,这样就能调用接口中的方法了
* handler, 将这个代理对象关联到了上方的 InvocationHandler 这个对象上,真正的执行者
*/
IUserDao proxy = (IUserDao) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),handler);
System.out.println("代理对象信息 "+proxy.getClass());
proxy.save();
}
}
输出结果
目标对象信息 class proxy.demo1.UserDao
代理对象信息 class com.sun.proxy.$Proxy0
开启事务
保存数据
提交事务
代理的作用
- 在不修改被代理对象的源码上,进行功能的增强(AOP最常见)
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
主要功能
日志记录,性能统计,安全控制,事务处理,异常处理等等。