结构性模式一共包括七种:
代理模式、桥接模式、装饰者模式、适配器模式、门面(外观)模式、组合模式、和享元模式。
1 代理模式介绍
软件开发中的代理:
代理模式中引入了一个新的代理对象,代理对象在客户端对象和目标对象之间起到了中介的作用,它去掉客户不能看到的内容和服务或者增加客户需要的额外的新服务.
2 代理模式原理
3 静态代理实现
举例:保存用户功能的静态代理实现
public interface IUserDao {void save();
}
/*** 目标类**/
public class UserDaoImpl implements IUserDao {@Overridepublic void save() {System.out.println("保存数据");}
}
/*** 代理类**/
public class UserDaoProxy implements IUserDao {private IUserDao target;public UserDaoProxy(IUserDao target) {this.target = target;}@Overridepublic void save() {System.out.println("开启事务"); //扩展额外的功能target.save();System.out.println("提交事务");}
}
/*** 静态代理* 优点: 可以在不修改目标类的前提下,扩展目标类的功能* 缺点:* 1.冗余.由于代理对象要实现和目标对象一致的接口,会产生很多的代理.* 2.不易维护.一旦接口中增加方法,目标对象和代理对象都要进行修改.*/@Testpublic void testStaticProxy(){//目标类IUserDao dao = new UserDaoImpl();//代理对象UserDaoProxy proxy = new UserDaoProxy(dao);proxy.save();}
4 JDK动态代理
举例:保存用户功能的静态代理实现
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(){return Proxy.newProxyInstance(//目标类使用的类加载器target.getClass().getClassLoader(),//目标对象实现的接口类型target.getClass().getInterfaces(),new InvocationHandler() { //事件处理器@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("开启事务");method.invoke(target,args);System.out.println("提交事务");return null;}});}
}
测试:
public static void main(String[] args) {IUserDao userDao = new UserDaoImpl();System.out.println(userDao.getClass()); //目标对象的信息IUserDao proxy = (IUserDao) new ProxyFactory(userDao).getProxyInstance();//获取代理对象System.out.println(proxy.getClass());proxy.save();//代理方法while (true){}}
5 类是如何动态生成的
6代理类的调用过程
我们通过借用阿里巴巴的一款线上监控诊断产品 Arthas(阿尔萨斯) ,对动态生成的代理类代码进行查看.
代理类代码如下:
package com.sun.proxy;import com.mashibing.proxy.example01.IUserDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0 extends Proxy implements IUserDao {private static Method m1;private static Method m3;private static Method m2;private static Method m0;public $Proxy0(InvocationHandler invocationHandler) {super(invocationHandler);}static {try { m1 = Class.forName("java.lang.Object").getMethod("equals",Class.forName("java.lang.Object"));m3 = Class.forName("com.mashibing.proxy.example01.IUserDao").getMethod("save", new Class[0]);m2 = Class.forName("java.lang.Object").getMethod("toString", newClass[0]);m0 = Class.forName("java.lang.Object").getMethod("hashCode", newClass[0]);return;}catch (NoSuchMethodException noSuchMethodException) {throw new NoSuchMethodError(noSuchMethodException.getMessage());}catch (ClassNotFoundException classNotFoundException){throw new NoClassDefFoundError(classNotFoundException.getMessage());}}public final boolean equals(Object object) {try {return (Boolean)this.h.invoke(this, m1, newObject[]{object});}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final String toString() {try {return (String)this.h.invoke(this, m2, null);}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final int hashCode() {try {return (Integer)this.h.invoke(this, m0, null);}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}public final void save() {try {this.h.invoke(this, m3, null);return;}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}
}
爲了方便理解简化后的代码:
package com.sun.proxy;import com.mashibing.proxy.example01.IUserDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0 extends Proxy implements IUserDao {private static Method m3;public $Proxy0(InvocationHandler invocationHandler) {super(invocationHandler);}static {try {m3 = Class.forName("com.mashibing.proxy.example01.IUserDao").getMethod("save", new Class[0]);return;}}public final void save() {try {this.h.invoke(this, m3, null);return;}}
}
7 cglib动态代理
使用cglib 需要引入cglib 的jar包,如果你已经有spring-core的jar包,则无需引入,因为spring中包含了cglib 。
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.5</version>
</dependency>
示例代码
目标类:
/*** 目标类**/
public class UserServiceImpl {//查询功能public List<User> findUserList(){return Collections.singletonList(new User("tom",23));}
}
cglib代理类,需要实现MethodInterceptor接口,并指定代理目标类target
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Calendar;
//在實現動態代理的同時擴展一個日志的功能
public class UserLogProxy implements MethodInterceptor {/*** 生成CGLIB动态代理类方法* @param target 需要被代理的目标类* @return: java.lang.Object 代理类对象*/public Object getLogProxy(Object target){//增强器类,用来创建动态代理类Enhancer enhancer = new Enhancer();//设置代理类的父类字节码对象enhancer.setSuperclass(target.getClass());//设置回调enhancer.setCallback(this);//创建动态代理对象,并返回return enhancer.create();}/*** 实现回调方法* @param o 代理对象* @param method 目标对象中的方法的Method实例* @param args 实际参数* @param methodProxy 代理类对象中的方法的Method实例* @return: java.lang.Object*/@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Calendar instance = Calendar.getInstance();SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println(format.format(instance.getTime()) + "[ " +method.getName() +"] 查询用户信息...");Object result = methodProxy.invokeSuper(o, args);return null;}
}
public class User {private String name;private int age;public User(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}
8 cglib代理流程
9代理模式总结
參考文章:
https://www.cnblogs.com/hg-blogs/p/17314887.html