代理:
静态代理:
手动生成代理对象,然后通过调用原对象的方法实现原业务的基础上,在前后加上相应的与业务逻辑无关的功能,比如开启事务;
动态代理:
动态代理又分为jdk代理以及cglib代理
jdk代理:
jdk代理是有jdk提供的自动生成代理对象的机制,他主要是通过反射的方式。首先我们需要定义一个处理器类,它需要实现InvocationHandler接口,然后重写invok方法;其中proxy表示代理方法,method表示method对象,args表示method方法的参数。
package org.handler; import org.service.Service; import org.service.impl.ServiceImpl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyHandler implements InvocationHandler { private Object obj; public MyHandler(Object obj){ this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("原方法运行前,可以在这里开启事务!"); //调用原方法 Object ret=method.invoke(obj,args); System.out.println("原方法运行结束,可以在这里关闭事务!"); return ret; } }
然后使用Proxy.newProxyInstance()可以得到代理对象,它需要三个参数,1类加载器:建议使用被代理类的类加载器,他可以保证代理类能正确的加载到内存中并与被代理类有相同的类结构。2.一组接口,代理对象实现这组接口使他有了多个接口的功能,并在原基础上进行扩展。3.处理器,实现增强功能。
public class Main_jdk_proxy { public static void main(String[] args) { Service service = (Service) Proxy.newProxyInstance( ServiceImpl.class.getClassLoader(), ServiceImpl.class.getInterfaces(), new MyHandler(new ServiceImpl()) ); service.doSomething(); } }
cglib代理:
jdk的代理虽然解决了静态代理中需要手动生成每个代理类以及多个代理就要实现多个代理类的缺点,但是假如我没有接口,但是我又想代理,或者说我想代理一些非公开的方法的时候,jdk代理是无法实现的,因为有接口的限制,代理对象只能拿到被代理对象的公开方法。那么这个时候,cglib就为此而生了。他使用的是继承的方式进行代理,因此,我们不需要接口,以及protected和默认方法也可以被继承,只有private不能被继承,我们也可以对protected和默认方法进行代理。
首先需要导入cglib依赖包
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
然后需要实现一个拦截器类,它实现了MethodInterceptor接口并重写intercept方法、并使用proxy.invokSuper()调用原始方法。
public class MyInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before method: " + method.getName()); Object result = proxy.invokeSuper(obj, args); //Object result=method.invoke(obj,args); System.out.println("After method: " + method.getName()); return result; } }
注意不能使用method.invok(),它会调用代理类的方法,而代理类的方法已经被重写,这会引起递归调用代理类的方法,从而陷入无限循环。
最后我们使用Enhancer生成代理对象,并调用代理对象的相应方法
Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Resource.class); enhancer.setCallback(new MyInterceptor()); Resource proxy = (Resource) enhancer.create(); proxy.sayHello();
总结
总结起来,JDK动态代理是基于接口的代理方式,使用Proxy类和反射机制,只能代理接口方法;而CGLIB代理是基于继承的代理方式,使用Enhancer类和字节码生成,可以代理类和接口方法。 选择使用哪种代理方式取决于具体的需求和场景。如果被代理的类已经实现了接口,且只需要代理接口中的方法,那么可以选择JDK动态代理。如果被代理的类没有实现接口,或者需要代理类中的方法,那么可以选择CGLIB代理。