什么是动态代理?
当我们需要给某个类或者接口中的方法添加一些额外的功能比如日志、事务的时候,可以通过创建一个代理类来实现这些功能;该代理类既包含了原有类的完整功能,同时在这些功能的基础上添加了其他的逻辑。这个代理类不是事先定义好的,而是动态生成的,比较灵活;
有几种动态代理
1.java动态代理
java动态代理有个缺点就是要被代理的类必须实现一个接口,否则没法代理
2.cglib动态代理
cglib动态代理可以对没有实现接口的类进行代理
动态代理的应用
AOP
在我们用到spring框架的时候碰到的aop前置后置通知都是基于动态代理来实现的,这里不细追。
如何编写动态代理案例?
我们使用java的动态代理来编写一个案例,主要分为以下几步:
1.编写一个常规方法的接口,这里我们定义一个用户接口,并且编写保存用户方法save()
/**
* 用户接口
*/
public interface UserDao {
public void save();//定义保存用户的方法
}
2.编写用户接口的实现类,并且实现接口方法save()
/**
* 用户接口实现类
*/
public class UserDaoImp implements UserDao {
@Override
public void save() {
System.out.println("保存用户");
System.out.println("保存成功啦");
}
}
3.编写自己的MyInvocationHandler实现InvocationHandler接口,重写invoke方法来添加我们需要添加的额外功能
public class MyInvocationHandler implements InvocationHandler {
//被动态代理的对象
private Object target;
public MyInvocationHandler(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;
}
}
4.通过Proxy来生成代理对象,有俩种方式
public static void main(String[] args) throws Exception {
/**
* 方式一
*/
//通过调用动态代理类Proxy的newProxyInstance()生成代理对象
UserDao userDao= (UserDao) Proxy.newProxyInstance(UserDao.class.getClassLoader(),
new Class<?>[] { UserDao.class }, // 被代理类的接口
new MyInvocationHandler(new UserDaoImp()));//要被代理的对象
userDao.save();
/**
* 方式二
*/
//编写invocationhandler实现额外功能
InvocationHandler handler = new MyInvocationHandler(new UserDaoImp());
//通过调用动态代理类Proxy的getProxyClass()方法获取要代理的类
Class<?> proxyClass = Proxy.getProxyClass(UserDao.class.getClassLoader(), UserDao.class);
//通过代理类生成代理对象
UserDao userDao1 = (UserDao) proxyClass.getConstructor(InvocationHandler.class).
newInstance(handler);
userDao1.save();
}
运行结果如下所示: