动态代理:在程序运行之前,代理类不存在,程序运行时,代理类时生成的。
cglib动态代理的效率要高于jdk动态代理,所以一般使用cglib 可以为任何类生成代理,可以不用实现接口 生成的代理类是目标类的子类,对外表现同样的功能 调用该代理类需要导入aspects包
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.1.15.RELEASE</version> </dependency>cglib代理类: 该类需要实现MethodInterceptor接口
public class CglibProxy implements MethodInterceptor{ //cglib动态代理 /** * proxy是代理对象 * method是目标对象的方法 * args是目标的方法参数 * */ @Override public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("befor target");//前置通知 Object r=proxy.invokeSuper(target, args);//调用目标对象的方法 System.out.println("after target");//后置通知 return r; }主方法:
public static void main(String[] args) { UserDao target1=new UserDaoImpl(); Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(UserDaoImpl.class);//设置目标类作为代理类的父类 enhancer.setCallback(new CglibProxy());//设置代理类 UserDao p1= (UserDao) enhancer.create();//生成代理对象 p1.insert(); }此代理类需要有一个特点,被代理的类必须有一个接口。 所以我们需要为类创建一个接口类
public interface UserDao { public boolean insert(); }下面时具体类
public class UserDaoImpl implements UserDao { @Override public boolean insert() { System.out.println("UserDaoImpl insert"); return true; } }动态代理:动态代理类需要实现InvocationHandler这个接口
public class JdkProxy implements InvocationHandler{ public Object target;//目标对象 public JdkProxy(Object target) { this.target = target; } @Override /** * proxy是代理对象 * method是目标对象的方法 * args是目标的方法参数 * */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before target");//前置通知 Object r=method.invoke(target, args);//反射调用目标对象的方法 System.out.println("arter target");//后置通知 return r; }下面是主方法:
public class App { public static void main(String[] args) { UserDao target1=new UserDaoImpl(); //jdk动态代理 //获取target1的代理对象 UserDao p1=(UserDao) Proxy.newProxyInstance(target1.getClass().getClassLoader(), target1.getClass().getInterfaces(), new JdkProxy(target1)); p1.insert();//调用代理对象的方法 } }获取代理对象的前两个参数简介如下:
是获取该类的装载器。我们都知道java程序写好以后是以.java(文本文件)的文件存在磁盘上,然后,我们通过(bin/javac.exe)编译命令把.java文件编译成.class文件(字节码文件),并存在磁盘上。但是程序要运行,首先一定要把.class文件加载到JVM内存中才能使用的,我们所讲的classLoader,就是负责把磁盘上的.class文件加载到JVM内存中
的功能是返回当前类或接口实现的接口。