一.动态代理
1.简介
- JDK动态代理的实现是在运行时,根据一组接口定义,使用Proxy、InvocationHandler等工具类去生成一个代理类和代理类实例。
- 需要建一个拦截器实现InvocationHandler接口重写invoke方法用来拦截并执行目标类业务
- 在拦截器里面提供有参构造函数,里面传入Object目标类和所有切面类对象
- 可以通过在拦截器里面增加切面类来增加功能(通知)
- 测试类里面Proxy.newProxyInstance(目标类加载器,目标类接口,拦截器)获得的就是和UserDaoImpl一样的UserDao代理对象
2.注意事项
- Jdk产生动态代理目标类UserDao必须实现一个接口UserImpl
- Jdk产生动态代理必须创建一个拦截器MyInterceptor,继承InvocationHandler接口,重写invoke方法来融合目标类和事务类,method.invoke(target,args)来调用目标类方法
- 代理类中使用JDK创建代理对象,Proxy.newProxyInstance(目标类,目标类接口,拦截器);
- 代理类的是作用是融合目标类方法和各种通知方法的集合
- 所有事务类里面的方法都叫通知,目标类方法前面执行的叫前置通知,目标类后面的叫后置通知
- 代理对象调用save方法,首先走的是拦截器里面的invoke方法
2.理解
3.好处
4.区别
二.代码
1.目标类接口
package com.jp.dao;
import com.jp.domain.User;
public interface UserDao {
void save(User user);
}
2.目标类(客户)
package com.jp.dao;
import com.jp.domain.User;
public class UserDaoImpl implements UserDao {
@Override
public void save(User user) {
//开启事务
//日志记录
//安全校验
System.out.println("保存用户成功");
//提交事务
}
}
3.事务类
package com.jp.transcation;
public class MyTranscation {
public void begin(){
System.out.println("开启事务");
}
public void commit(){
System.out.println("提交事务");
}
}
package com.jp.transcation;
public class Loggle {
public void log(){
System.out.println("日志记录");
}
}
package com.jp.transcation;
public class Security {
public void safe(){
System.out.println("安全校验");
}
}
4.拦截器
继承InvocationHandler接口,实现invoke方法
package com.jp.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import com.jp.transcation.Loggle;
import com.jp.transcation.MyTranscation;
import com.jp.transcation.Security;
public class MyInterceptor implements InvocationHandler{
private Object target; //目标类UserDaoImpl
private MyTranscation myTranscation; //事务类(切面)
private Loggle log; //日志类
private Security security; //安全校验类
//有参构造
public MyInterceptor(Object target, MyTranscation myTranscation,Loggle log, Security security) {
super();
this.target = target;
this.myTranscation = myTranscation;
this.log = log;
this.security = security;
}
//proxy是代理类对象,method封装目标类的方法,args是目标类的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
myTranscation.begin(); //开启事务
log.log(); //日志记录
security.safe(); //安全校验
method.invoke(target, args);//调用目标类方法
myTranscation.commit(); //提交事务
return null;
}
}
5.测试类
package com.jp.test;
import java.lang.reflect.Proxy;
import com.jp.dao.UserDao;
import com.jp.dao.UserDaoImpl;
import com.jp.domain.User;
import com.jp.jdkproxy.MyInterceptor;
import com.jp.transcation.Loggle;
import com.jp.transcation.MyTranscation;
import com.jp.transcation.Security;
public class JdkProxyTest {
public static void main(String[] args) {
//创建目标对象
UserDao userDao=new UserDaoImpl();
//创建事务对象
MyTranscation myTranscation=new MyTranscation();
//创建日志对象
Loggle log=new Loggle();
//创建安全校验对象
Security security=new Security();
//创建拦截器对象
MyInterceptor myInterceptor=new MyInterceptor(userDao,myTranscation,log,security);
//JDK帮忙创建代理对象
//代理类将目标类和事务类通过拦截器的invoke方法融合到一起
//第一个参数:目标类加载器.第二个参数:获得目标类的所有接口.第三个参数:拦截器
UserDao userDaoProxy = (UserDao)Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), myInterceptor);
User user=new User();
//代理对象调用save方法,首先走的是拦截器里面的invoke方法
userDaoProxy.save(user);
}
}