第六章、动态代理设计模式
一、代理的概念
代理的本质:在不改变目标类方法的代码的情况下对目标类的方法进行增强.
为其他对象提供一个代理以控制对某个对象的访问。代理类主要负责为委托了(真实对象)预处理消息、过滤消息、传递消息给委托类,代理类不现实具体服务,而是利用委托类来完成服务,并将执行结果封装处理。
二、静态代理
由程序员写的代理类,在运行前代理类的.class文件已经存
(一)静态代理的角色
1.接口
目标类和代理类都要实现该接口
2.目标类
被代理的类
3.代理类
代理目标类的类
4.测试类
创建目标对象
创建代理对象,注入目标对象
调用代理类的方法
(二)静态代理的使用
public interface UserDao {
void add();
void update();
void del();
}
//目标类实现接口
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("UserDaoImpl.add()...");
System.out.println(1/0);
}
@Override
public void update() {
System.out.println("UserDaoImpl.update()...");
}
@Override
public void del() {
System.out.println("UserDaoImpl.del()...");
}
}
代理类:
有目标类对象的成员变量
通过构造方法传入目标类对象的引用
代理类方法调用目标类对象的方法
public class UserDaoProxy implements UserDao {
private UserDao obj;
public UserDaoProxy(UserDao obj) {
super();
this.obj = obj;
}
public UserDaoProxy() {
// TODO Auto-generated constructor stub
}
@Override
public void add() {
System.out.println("开启事务");//前置增强
try {
obj.add();//调用目标类的方法
System.out.println("提交事务");//后置增强
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("例外增强");
}finally{
System.out.println("最终增强");
}
}
@Override
public void update() {
// TODO Auto-generated method stub
System.out.println("开启事务");//前置增强
obj.update();//调用目标类的方法
System.out.println("提交事务");//后置增强
}
@Override
public void del() {
// TODO Auto-generated method stub
System.out.println("开启事务");//前置增强
obj.del();//调用目标类的方法
System.out.println("提交事务");//后置增强
}
}
代理类:
public static void main(String[] args) {
//1.创建目标类对象
UserDao obj=new UserDaoImpl();
//2.创建代理对象
UserDao proxy=new UserDaoProxy(obj);
//3.调用代理类对象的方法
proxy.add();
}
(三)静态代理的缺点
- 接口增加方法,目标类和代理类都要实现方法,增加了代码维护的复杂度
- 增加代理类型需要写另外一个代理类去代理,这又导致代理类型的复杂度.
三、动态代理
在程序运行时运用反射机制动态创建而成,不是提前写好的,是后期动态生成的。
java中动态代理主要有JDK和CGLIB两种方式
(一)JDK动态代理
是代理模式的一种实现方式,其只能代理接口
由图可以简单的知道调用代理类中的所有方法实际上都是调用中间类的invoke方法,而在invoke方法中才是真正去调用对应的目标类的目标方法;这个比静态代理多了一层结构
动态代理底层实现
动态代理具体步骤:
- 通过实现 InvocationHandler 接口创建自己的调用处理器;
- 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
- 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
- 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
JDK动态代理使用
- 新建一个接口
- 为接口创建一个实现类(就是被代理的类,即目标类)
- 创建中间类实现java.lang.reflect.InvocationHandler接口
public interface UserDao {
void add();
void update();
void del();
}
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("UserDaoImpl.add()...");
System.out.println(1/0);
}
@Override
public void update() {
System.out.println("UserDaoImpl.update()...");
}
@Override
public void del() {
System.out.println("UserDaoImpl.del()...");
}
}
public class JdkProxy implements InvocationHandler{
private Object obj;
public JdkProxy(Object obj) {
super();
this.obj = obj;
}
public JdkProxy() {
// TODO Auto-generated constructor stub
}
/**
* proxy:代理对象,由JDK的 Proxy.newProxyInstance()生成
* method:代理对象传进来的方法对象
* Object[] args:代理对象传进来的方法参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//调用目标对象的方法
Object invoke = null;
try {
//前置增强
System.out.println("开启事务");
invoke = method.invoke(obj, args);
//后置增强
System.out.println("提交事务");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("例外增强");
}finally{
System.out.println("最终增强");
}
return invoke;
}
}
public static void main(String[] args) {
//1.创建目标类对象
Object obj=new UserDaoImpl();
//2.创建代理对象
UserDao proxy=(UserDao) Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), new JdkProxy(obj));
System.out.println(proxy.getClass());
//3.调用代理类对象的方法
proxy.add();
proxy.update();
proxy.del();
}
(二)CGLIB动态代理
CGLib动态代理是代理类去继承目标类,然后重写其中目标类的方法,这样也可以保证代理类拥有目标类的同名方法。
代理类去继承目标类,每次调用代理类的方法都会被方法拦截器拦截,在拦截器中才是调用目标类的该方法的逻辑。
CGLIB动态代理使用
public class UserDaoImpl {
public void add() {
System.out.println("UserDaoImpl.add()...");
System.out.println(1/0);
}
public void update() {
System.out.println("UserDaoImpl.update()...");
}
public void del() {
System.out.println("UserDaoImpl.del()...");
}
}
引入cglib的maven依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
写方法拦截器类(相当于中间类)实现MethodInterCeptor接口
public class MyMethodInterCeptor implements MethodInterceptor {
/**
* Object proxy:代理对象
* Method method:代理对象传进来的方法对象
* Object[] args:代理对象传进来的方法参数
* MethodProxy methodProxy:方法代理对象,是cglib对method对象进行了封装增强,性能好
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
//调用目标类的方法
Object invokeSuper = null;
try {
//前置增强
System.out.println("开启事务");
invokeSuper = methodProxy.invokeSuper(proxy, args);
//后置增强
System.out.println("提交事务");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
//后置增强
System.out.println("例外增强");
}finally{
System.out.println("最终增强");
}
return invokeSuper;
}
}
public static void main(String[] args) {
//创建目标类对象
Object obj=new UserDaoImpl();
//创建Enhancer对象,该对象用来生成代理对象
Enhancer enhancer = new Enhancer();
//设置被代理卖的类
enhancer.setSuperclass(obj.getClass());
//设置回调对象(相当于jdk的中间类对象)
enhancer.setCallback(new MyMethodInterCeptor());
//调用enhancer对象的create()方法,通过动态字节码技术生成目标类的子类对象就是代理对象
UserDaoImpl proxy=(UserDaoImpl) enhancer.create();
System.out.println(proxy.getClass());
//调用代理对象的方法
proxy.add();
proxy.update();
proxy.del();
}