zoukankan      html  css  js  c++  java
  • JDK代理和CGLIB代理

    学而时习之,不亦说乎!

                                 --《论语》

    AOP是spring的一个重要组成部分,而AOP通过代理实现。这儿写下JDK代理和CGLIB代理两种动态代理,为接下来的Spring AOP做准备。

    JDK代理:

    1)项目整体结构如下:

    2)创建maven项目,pom.xml如下:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<groupId>com.zby</groupId>
    	<artifactId>aop</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<dependencies>
    		<!-- https://mvnrepository.com/artifact/cglib/cglib -->
    		<dependency>
    			<groupId>cglib</groupId>
    			<artifactId>cglib</artifactId>
    			<version>3.2.5</version>
    		</dependency>
    	</dependencies>
    </project>

    这个依赖主要是给CGLIB用的,JDK代理并不需要。

    3)创建UserService接口:

    package com.zby.service;
    
    public interface UserService {
    
    	void saveUser(String username, String password);
    }
    

    4)创建UserService接口实现类UserServiceImpl:

    package com.zby.service.impl;
    
    import com.zby.service.UserService;
    
    public class UserServiceImpl implements UserService {
    
    	public void saveUser(String username, String password) {
    		System.out.println("save user[username=" + username + ",password=" + password + "]");
    	}
    
    }
    

    5)创建CustomAspect切面类:

    package com.zby.aspect;
    
    public class CustomAspect {
    
    	public void startTransaction() {
    		System.out.println("I get datasource here and start transaction");
    	}
    
    
    
    	public void endTrasaction() {
    		System.out.println("I get datasource here and end transaction");
    	}
    }
    

    6)创建JDKProxy代理工厂:

    package com.zby.factory;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import com.zby.aspect.CustomAspect;
    
    public class JDKProxy {
    
    	public static Object createProxy(final Object targetObj, final CustomAspect customAspect) {
    		// 使用JDK的Proxy类为目标类创建代理对象
    		return Proxy.newProxyInstance(
    				// 目标类使用的类加载器
    				targetObj.getClass().getClassLoader(),
    				// 目标类实现的接口
    				targetObj.getClass().getInterfaces(),
    				// 执行处理器,代理我们的业务逻辑
    				new InvocationHandler() {
    					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    						// 执行切面方法
    						customAspect.startTransaction();
    						// 具体逻辑代码执行,返回值为方法执行结果
    						Object result = method.invoke(targetObj, args);
    						// 执行切面方法
    						customAspect.endTrasaction();
    						// 返回方法执行结果
    						return result;
    					}
    				});
    	}
    }
    

      

    7)编写测试代码:

    package com.zby.test;
    
    import org.junit.Test;
    
    import com.zby.aspect.CustomAspect;
    import com.zby.factory.JDKProxy;
    import com.zby.service.UserService;
    import com.zby.service.impl.UserServiceImpl;
    
    public class JDKProxyTest {
    	@Test
    	public void testJDKProxy() {
    		System.out.println("before Proxy......");
    		UserService userService = new UserServiceImpl();
    		userService.saveUser("zby", "1234567890");
    		System.out.println("After Proxy......");
    		UserService proxyUserService = (UserService)JDKProxy.createProxy(userService, new CustomAspect());
    		proxyUserService.saveUser("zby", "1234567890");
    	}
    }
    

    8)控制台打印结果:

    before Proxy......
    save user[username=zby,password=1234567890]
    After Proxy......
    I get datasource here and start transaction
    save user[username=zby,password=1234567890]
    I get datasource here and end transaction
    

    CGLIB代理:

    1)使用JDK代理创建的UserService接口,UserServiceImpl实现类和CustomAspect切面类。

    2)创建CGLIB的代理类CGLIBProxy:

    package com.zby.factory;
    
    import java.lang.reflect.Method;
    
    import com.zby.aspect.CustomAspect;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class CGLIBProxy {
    
    	public static Object createProxy(final Object targetObj, final CustomAspect customAspect) {
    		Enhancer enhancer = new Enhancer();
    		// 设置需要代理的父类
    		enhancer.setSuperclass(targetObj.getClass());
    		// 设置回调
    		enhancer.setCallback(new MethodInterceptor() {
    			@Override
    			public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
    					throws Throwable {
    				// 执行切面方法
    				customAspect.startTransaction();
    				// 具体逻辑代码执行,返回值为方法执行结果
    				Object result = methodProxy.invokeSuper(proxy, args);
    				// 执行切面方法
    				customAspect.endTrasaction();
    				// 返回方法执行结果
    				return result;
    			}
    		});
    		// 3.4 创建代理
    		return enhancer.create();
    	}
    }
    

    3)编写测试类:

    package com.zby.test;
    
    import org.junit.Test;
    
    import com.zby.aspect.CustomAspect;
    import com.zby.factory.CGLIBProxy;
    import com.zby.service.UserService;
    import com.zby.service.impl.UserServiceImpl;
    
    public class CGLIBProxyTest {
    	@Test
    	public void testJDKProxy() {
    		System.out.println("before Proxy......");
    		UserService userService = new UserServiceImpl();
    		userService.saveUser("zby", "1234567890");
    		System.out.println("After Proxy......");
    		UserService proxyUserService = (UserService) CGLIBProxy.createProxy(userService, new CustomAspect());
    		proxyUserService.saveUser("zby", "1234567890");
    	}
    }
    

    4)控制台打印结果:

    before Proxy......
    save user[username=zby,password=1234567890]
    After Proxy......
    I get datasource here and start transaction
    save user[username=zby,password=1234567890]
    I get datasource here and end transaction
    

     5)CGLIB代理和JDK代理最大的区别就是:CGLIB代理的对象不需要实现任何接口,它使用的字节码子类代理方式,但是JDK代理的对象必须实现接口。这儿使用CGLIB代理的时候,可以将UserService删除,使用UserServiceImpl接收代理结果,效果完全一样。

    6)JDK代理的实质是生成一个实现我们传入的接口,并且继承Proxy的类;Cglib代理实质是继承我们传入的类。

  • 相关阅读:
    班会记录
    CSS之伪元素
    JavaScript之返回顶部
    尝试Hexo
    GitHub之上传文件
    Git之使用
    Git之基本命令
    运行第一个Node.js程序
    go语言圣经 map 章节习题
    go语言圣经第4章JSON部分习题
  • 原文地址:https://www.cnblogs.com/zby9527/p/6945756.html
Copyright © 2011-2022 走看看