spring的代理模式

代理模式

代理模式分为:静态代理、Jdk动态代理、CGlib动态代理三种代理模式

比较三种代理:

静态代理是通过在代码中显式定义一个业务实现类一个代理,在代理类中对同名的业务方法进行包装,用户通过代理类调用被包装过的业务方法;
​ JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;
​ CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理;

1.1 静态代理

创建接口

public interface UserService {
    public void addUser(String a);
    public void updateUser(String b);
}

1.1.2 创建实现类

public class UserServiceImpl implements UserService{
    public void addUser(String a) {
        System.out.println("新增用户");
    }

    public void updateUser(String a) {
        System.out.println("修改用户");
    }
}

1.1.3 创建静态代理类

public class UserProxyHandle implements UserService {

    private UserServiceImpl userServiceImpl;

    public UserProxyHandle(UserServiceImpl userServiceImpl) {
        this.userServiceImpl = userServiceImpl;
    }

    public void addUser(String a) {
        System.out.println("新增用户前的操作");
        userServiceImpl.addUser(a);
        System.out.println("新增用户后的操作");
    }

    public void updateUser(String b) {
        System.out.println("修改用户前的操作");
        userServiceImpl.updateUser(b);
        System.out.println("修改用户后的操作");
    }
}

1.1.4 测试调用

  @Test
    public void test01(){
        //静态代理模式
        UserServiceImpl userService = new UserServiceImpl();
        UserProxyHandle userProxyHandle = new UserProxyHandle(userService);
        userProxyHandle.addUser();
        userProxyHandle.updateUser();
      
    }

1.1.5 缺点

静态代理的缺点很明显:一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就要定义很多实现类和代理类才行。而且,如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码。这时我们可以定义这样一个代理类,它能代理所有实现类的方法调用:根据传进来的业务实现类和方法名进行具体调用。——那就是动态代理

1.1.5 缺点

1.2.1 jdk动态代理原理

**JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象 以及 方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。**我们需要做的,只需指定代理类的预处理、调用后操作即可。

1.2.2 定义接口

与上方相同即可

1.2.3 创建实现类

与上方相同即可

1.2.4 实现调用管理接口InvocationHandler创建动态代理类

public class JdkProxyHandle implements InvocationHandler {
    private Object target;//这其实业务实现类对象,用来调用具体的业务方法
    public Object bind(Object obj){
    this.target=obj;
        //通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
        //创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
    return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
    }


    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("调用方法前");
        Object invoke = method.invoke(target,args);
        System.out.println("调用方法后");
        return invoke;
    }
}

1.2.5 测试

  @Test
    public void test01(){
        //动态代理模式 jdk
        UserServiceImpl userService = new UserServiceImpl();
        JdkProxyHandle jdkProxyHandle = new JdkProxyHandle();
        UserService bind = (UserService) jdkProxyHandle.bind(userService);
        bind.addUser("1");
        bind.updateUser("2");
    }

1.2.6 缺点

JDK动态代理的代理对象在创建时,需要使用业务实现类所实现的接口作为参数(因为在后面代理方法时需要根据接口内的方法名进行调用)。如果业务实现类是没有实现接口而是直接定义业务方法的话,就无法使用JDK动态代理了。并且,如果业务实现类中新增了接口中没有的方法,这些方法是无法被代理的(因为无法被调用)。

1.3 CGlib动态代理

1.3.1 cglib实现原理

使用JDK创建代理有一个限制,它只能为接口创建代理实例.这一点可以从Proxy的接口方法 newProxyInstance(ClassLoader loader,Class [] interfaces,InvocarionHandler h)中看的很清楚

​ 第二个入参 interfaces就是需要代理实例实现的接口列表.

​ 对于没有通过接口定义业务方法的类,如何动态创建代理实例呢? JDK动态代理技术显然已经黔驴技穷,CGLib作为一个替代者,填补了这一空缺.

​ GCLib采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势志入横切逻辑.

1.3.2 定义业务类,无需实现接口(实现接口也可以,不影响)

与上方相同即可

1.3.3 实现MethodInterceptor方法代理接口,创建代理类

public class CglibProxyHandle implements MethodInterceptor {
	
    private Object target;
    //设置被代理对象
    public Object instance(Object obj){
        this.target =obj;
        //创建加强器,用来创建动态代理类
        Enhancer enhancer = new Enhancer();
        //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        enhancer.setSuperclass(obj.getClass());
   //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方		//法进行拦
        enhancer.setCallback(this);
        // 创建动态代理类对象并返回
        Object o = enhancer.create();
        return o;
    }

 // 实现回调方法 
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib 执行方法前");
        //调用业务类(父类中)的方法
        Object o1 = methodProxy.invokeSuper(o, objects);
        System.out.println("cglib 执行方法后");
        return o1;
    }
}

1.3.4 测试

@Test
 public  void test2(){
    //TODO CGlib实现
    	UserServiceImpl user= new UserServiceImpl();
        CglibProxyHandle cglibProxyHandle = new CglibProxyHandle();
        UserServiceImpl userService = (UserServiceImpl)cglibProxyHandle.instance(user);
        userService.addUser("a");
 }

你可能感兴趣的:(spring,java,spring,java)