代理模式: 在某些情况下,一个客户不想或者不能直接引用一个对 象,此时可以通过一个称之为“代理”的第三者来实现 间接引用。代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。
静态代理
静态代理: 最简单的代理模式,这种模式下,代理类和被代理类必须要实现或集成同一个类(这样代理与被代理类中就有同一个方法了,那么代理类可以在调用被代理类的方法同时再增强该方法)。并且代理类需要聚合被代理类(因为代理类需要调用被代理类中的方法)。
缺点: 静态代理必须自己手动创建代理类(Proxy);
//公共接口
public interface Image {
void display();
}
//被代理类
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
}
//代理类
public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(fileName);
}
System.out.prient("我是代理类增强代码");
realImage.display();
}
}
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
image.display();
}
}
JDK动态代理(需要实现类)
JDK动态代理: 必须要有接口类(interface),否则无法使用JDK动态代理;
/**
* 被代理的接口
*/
public interface TeacherDao {
String getName(String name);
}
/**
* 被代理的接口实现类
*/
public class TeacherDaoImpl implements TeacherDao{
public String getName(String name) {
return name;
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 创建代理对象
*/
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance() {
/*
参数1:类加载器
参数2:类实现的接口
参数3:方法执行器
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res = method.invoke(target, args);
return res+"6666";
}
});
}
}
//测试类
public class Client {
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory(new TeacherDaoImpl());
TeacherDao proxyFa = (TeacherDao) proxyFactory.getProxyInstance();
System.out.println(proxyFa.getName("leiqiang"));
}
}
JDK动态代理(无实现类Mybatis那种)
//被代理的接口
public interface IHello {
String say(String aa);
}
//创建代理类
public class FacadeProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("接口方法调用开始");
//执行方法
System.out.println("method toGenericString:"+method.toGenericString());
System.out.println("method name:"+method.getName());
System.out.println("method args:"+(String)args[0]);
System.out.println("接口方法调用结束");
return "调用返回值";
}
public static <T> T newMapperProxy(Class<T> mapperInterface) {
ClassLoader classLoader = mapperInterface.getClassLoader();
Class<?>[] interfaces = new Class[]{mapperInterface};
FacadeProxy proxy = new FacadeProxy();
return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);
}
}
//测试
public class Test {
public static void main(String[] args) {
IHello hello = FacadeProxy.newMapperProxy(IHello.class);
System.out.println(hello.say("hello world"));
}
}
cglib动态代理
cglib动态代理: 和JDK动态代理的区别是,不需要有接口类(interface),只需要知道实现类就能做到动态代理。
cglib参考:https://www.cnblogs.com/wyq1995/p/10945034.html
JDK和cglib区别:https://blog.csdn.net/xlgen157387/article/details/82497594
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
/**
* 被代理类
*/
public class Dog{
final public void run(String name) {
System.out.println("狗"+name+"----run");
}
public void eat() {
System.out.println("狗----eat");
}
}
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 生成代理类
*/
public class ProxyFactroy implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("这里是对目标类进行增强!!!");
//注意这里的方法调用,不是用反射哦!!!
Object object = proxy.invokeSuper(obj, args);
return object;
}
}
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
public class Test {
public static void main(String[] args) {
//在指定目录下生成动态代理类,我们可以反编译看一下里面到底是一些什么东西
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\tempFile");
//创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数
Enhancer enhancer = new Enhancer();
//设置目标类的字节码文件
enhancer.setSuperclass(Dog.class);
//设置回调函数
enhancer.setCallback(new ProxyFactroy());
//这里的creat方法就是正式创建代理类
Dog proxyDog = (Dog)enhancer.create();
//调用代理类的eat方法
proxyDog.eat();
}
}
JDK代理和CGlib代理的区别
- jdk代理会生成一个代理class文件,实现了一个接口类,在这个代理class文件中会反射调用我们原本的方法;
- CGlib代理会生成3个class文件,它是继承我们的代理类,然后通过字节码技术去重写我们被代理的方法;
区别
- 速度区别:jdk在生成文件时速度更快,但是最终是反射调用,速度慢;
- CGlib需要生成3个文件,这个时候慢,但是调用方法时,是调用的重写方法,速度更快;
- 所以在AOP中,使用CGlib原则上效率更高,因为AOP代理是在IOC启动时就会生成文件,所以在业务使用时,效率更高;