目录
0x00前置知识
反射是框架的灵魂
java反射:
反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制
0x01jdk动态代理
//切入点:insert方法
//切面类:UserDao
public interface UserDao {
void insert();
}
//实现类
public class UserDaoImpl implements UserDao{
@Override
public void insert() {
System.out.println("UserDao插入方法");
}
}
//处理器
public class Handler implements InvocationHandler {
Object object;
public Handler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd:hh:mm:ss");
String format = dateFormat.format(date);
System.out.println(format+"开启事务");
Object invoke = method.invoke(object, args);
Date date2 = new Date();
String format1 = dateFormat.format(date2);
System.out.println(format1+"提交事务");
return invoke;
}
}
public class Test {
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
Handler handler = new Handler(userDao);
UserDao user = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), handler);
user.insert();
}
}
第二种方法
public class JDKDynamic implements InvocationHandler {
Object object;
public JDKDynamic(Object object) {
this.object = object;
}
public Object getProxy(){
UserDao userDao = (UserDao) Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
return userDao;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd:hh:mm:ss");
String format = dateFormat.format(date);
System.out.println(format+"开启事务");
Object invoke = method.invoke(object, args);
Date date2 = new Date();
String format1 = dateFormat.format(date2);
System.out.println(format1+"提交事务");
return invoke;
}
}
public class Test2 {
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
UserDao proxy = (UserDao) new JDKDynamic(userDao).getProxy();
proxy.insert();
}
}
两种方法的区别在于生成代理对象和拦截器实现
方法一 将生成代理对象 Proxy.newProxyInstance(类加载器,接口,处理器)和拦截器分离
方法二则是封装到一起
实现步骤
1.获取类处理器
2.获取类实现接口
3.Proxy.newProxyInstance(类加载器,接口,invoke) 生成代理对象
4.代理对象调用方法 进入到拦截器
5.拦截器通过反射执行被代理对象方法 并添加通知
0x02CGLib动态代理
JDK动态代理是面向接口的代理模式,如果被代理目标没有实现接口就没办法
CGLib动态代理是通过字节码底层继承要代理类(子类)来实现,因此如果被代理类被final关键字所修饰会失败。
JDK动态代理需要实现InvocationHandler接口 重写invoke方法
CGLib动态代理需要实现MethodInterceptor接口 重写intercept方法
public class User {
public void insert(){
System.out.println("插入数据");
}
}
public class MethodHandler implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd:hh:mm:ss");
String begin = simpleDateFormat.format(date);
System.out.println("开启事务:"+begin);
Object invoke = methodProxy.invokeSuper(o,objects);
Date date1= new Date();
String end = simpleDateFormat.format(date1);
System.out.println("提交事务:"+end);
return invoke;
}
}
public class Test {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(User.class);
enhancer.setCallback(new MethodHandler());
User user= (User) enhancer.create();//生成代理对象
user.insert();
}
}
方法二
public class CGLibDynamicProxy implements MethodInterceptor {
Object object;
public CGLibDynamicProxy(Object object) {
this.object = object;
}
public Object getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(object.getClass());
enhancer.setCallback(this);
Object proxy = enhancer.create();
return proxy;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//obj是代理后的子类 ,method是调用方法 ,args是方法入参 , proxy是MethodProxy代理对象
System.out.println("开启事务");
Object invoke = method.invoke(object,objects);
System.out.println("提交事务");
return invoke;
}
}
public class Test2 {
public static void main(String[] args) {
User user = new User();
User user1 = (User) new CGLibDynamicProxy(user).getProxy();
user1.insert();
}
}
两种方法除了生成代理对象方法封装的不一样外,还有在进行反射时 调用的 invoke 和 invokeSuper
invoke 参数为父类对象
invokeSuper 参数为被代理子类对象(动态代理对象)