Java两种动态代理方式的使用

动态代理

  1. 作用:在不改变源码的基础上,对原有的方法进行增强实现,也是后面Spring AOP面向切面编程思想的实现技术
  2. 分类:JDK提供的动态代理(基于接口的动态代理)、cglib提供的动态代理(基于子类的动态代理)
  3. 实例代码:使用两种代理方式分别对下面的UserServiceImpl类进行增强

UserService接口类

package com.bran.service;

public interface UserService {

    void save();//保存操作
	
	void delete();//删除操作
	
	void update();//更新操作
	
	void find();//查找操作
}

UserServiceImpl类

package com.bran.service;

public class UserServiceImpl implements UserService {

	@Override
	public void save() {
		System.out.println("保存操作");
	}

	@Override
	public void delete() {
	    System.out.println("删除操作");
	}

	@Override
	public void update() {
		System.out.println("更新操作");
	}

	@Override
	public void find() {
		System.out.println("查找操作");
	}
	
}

 

JDK提供的动态代理

  1. 特点:基于接口的动态代理,并且只能对实现接口里面的方法进行增强
  2. 要求:被代理类必须实现至少一个接口
  3. 提供者:JDK自带
  4. 步骤:创建UserServiceProxyFactory类,用来生成动态代理对象
    package com.bran.proxytest;
    
    import com.bran.service.UserService;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    
    // JDK动态代理
    public class UserServiceProxyFactory implements InvocationHandler {
    	
    	private UserService userService;
    
    	//传入被代理对象
    	public UserServiceProxyFactory(UserService userService) {
    		super();
    		this.userService = userService;
    	}
    
        /**
         * 获取UserService的代理对象
         * 创建代理对象的方式为Proxy.newProxyInstance(ClassLoader loader,
         *                                           Class<?>[] interfaces,
         *                                           InvocationHandler h)
         * 需要传入3个参数值
         * ClassLoader loader:被代理对象的类加载器,一般是固定写法
         * Class<?>[] interfaces:被代理类实现的所有接口,要求被代理类最少实现一个接口,固定写法
         * InvocationHandler h :一个接口,要传入该接口的实现类对象,里面invoke方法里要写着对代理对象的方法的具体增强
         * @return
         */
    	public UserService getUserServiceProxy() {
    		//创建代理对象
    		UserService userServiceProxy = (UserService) Proxy.newProxyInstance(
    				userService.getClass().getClassLoader(),
    				userService.getClass().getInterfaces(),
    				this);
    		return userServiceProxy;
    	}
    
        /**
         * 执行被代理对象的任何接口方法时都会经过该方法(只能对接口方法增强)
         * @param proxy  代理对象的引用(给JDK使用的,一般我们用不到)
         * @param method 当前执行的方法
         * @param args 当前执行方法所需要的参数
         * @return
         * @throws Throwable
         */
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		//对方法进行增强实现
    		System.out.println("==========================");
    		System.out.println("打开事务");
    		Object returnValue = method.invoke(userService, args);//利用反射执行方法
    		System.out.println("提交事务");
                    System.out.println("==========================");
    		//也可以对UserServiceImpl类的特定方法进行增强
    //		if("delete".equals(method.getName())) {
    //			System.out.println("222222222222222");
    //		}
    //		Object invoke = method.invoke(userService, args);
    		return returnValue;
    	}
    
    }
    

    测试类

    package com.bran.proxytest;
    
    import com.bran.service.UserService;
    import com.bran.service.UserServiceImpl;
    import org.junit.Test;
    
    
    //测试JDK动态代理
    public class Demo {
    	@Test
    	public void testProxy() {
    	//创建被代理对象
    	UserService service = new UserServiceImpl();
    	UserServiceProxyFactory proxyFactory = new UserServiceProxyFactory(service);
            //生成代理对象
    	UserService proxyUserService = proxyFactory.getUserServiceProxy();
            //执行方法
            proxyUserService.delete();
            proxyUserService.find();
            //判断代理对象和被代理类的关系
            System.out.println(proxyUserService instanceof UserService);
    	System.out.println(proxyUserService instanceof UserServiceImpl);
    	}
    
    }
    

    输出结果

  5. 结果分析:由结果看出,代理对象的方法都是已经对被代理类的方法进行加强过的,模拟添加了打开事务和提交事务的操作;代理类和被代理类只是实现同一个接口,且代理对象不是被代理类的实例。所以被代理类里的不是实现接口的方法是不能进行代理的。

 

cglib提供的动态代理

  1. 特点;基于子类的动态代理,通过继承被代理类来重写方法从而对方法的增强,被final修饰的方法不能增强,不需要被代理类实现接口
  2. 要求:被代理类不能是最终类,不能被final修饰,必须是可继承的
  3. 提供者:cglib
  4. 使用要求:必须导入cglib的包才能使用cglib动态代理
    <!-- 使用Maven导入cglib的包-->
    <!-- https://mvnrepository.com/artifact/cglib/cglib -->
    <dependency>
       <groupId>cglib</groupId>
       <artifactId>cglib</artifactId>
       <version>3.2.12</version>
    </dependency>

     

  5. 步骤:创建UserServiceProxyFactory类,用来生成动态代理对象

    package com.bran.proxytest;
    
    import com.bran.service.UserService;
    import com.bran.service.UserServiceImpl;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    
    //cglib代理
    public class UserServiceProxyFactory implements MethodInterceptor {
    
        private UserServiceImpl userServiceImpl;
    
        //传入要代理的对象
        public UserServiceProxyFactory(UserServiceImpl userServiceImpl) {
            super();
            this.userServiceImpl = userServiceImpl;
        }
    
        /**
         * 获取UserService的代理对象
         * 创建代理对象的方式为Enhancer.create(Class type, Callback callback);
         * 参数:
         * Class type :指定被代理对象的字节码
         * Callback callback:一个接口,一般都是传入该接口的子接口MethodInterceptor的实现类对象,里面写对方法增强的具体实现
         *
         * @return
         */
        public UserServiceImpl getUserServiceImpl() {
    
            UserServiceImpl proxyUserServiceImpl = (UserServiceImpl) Enhancer.create(userServiceImpl.getClass(), this);//创建代理对象
    		/*
    		//也可以这种方式创建代理对象,两种方式是一样的
    	    Enhancer en = new Enhancer();//创建代理对象生成器,可以动态生成代理对象
    		en.setSuperclass(userService.getClass());//设置对谁进行代理
    		en.setCallback(this);//代理要做什么
            UserService proxyUserService = (UserService) en.create();//创建代理对象
            */
            return proxyUserServiceImpl;
    
        }
    
        /**
         * 执行被代理对象的方法时都会执行该方法
         * @param proxyobj  代理对象的引用
         * @param method  当前执行的方法
         * @param args 当前执行方法所需要的参数
         * @param methodProxy 当前执行方法的代理对象,是cglib生成对method的一个代理,可以用也可以不用
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Object proxyobj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            //对方法进行增强实现
            System.out.println("==========================");
            System.out.println("打开事务");
            Object returnValue = methodProxy.invokeSuper(proxyobj, args);//执行被代理对象的方法,要传入的是代理对象
            /**
             * 也可以这么写
             * Object returnValue = methodProxy.invoke(userService, args);//执行当前方法,要传入被代理对象
             * Object returnValue = method.invoke(userService, args);
             */
    
            System.out.println("提交事务");
            System.out.println("==========================");
            return returnValue;
        }
    
    }
    

    测试类

    package com.bran.proxytest;
    
    import com.bran.service.UserService;
    import com.bran.service.UserServiceImpl;
    import org.junit.Test;
    
    
    public class Demo {
    	@Test
    	public void testProxy() {
            //创建被代理对象
            UserServiceImpl userService = new UserServiceImpl();
            UserServiceProxyFactory proxyFactory = new UserServiceProxyFactory(userService);
            //生成代理对象
            UserServiceImpl proxyUserService = proxyFactory.getUserServiceImpl();
            proxyUserService.update();
            proxyUserService.save();
            System.out.println(proxyUserService instanceof UserServiceImpl);
    	}
    }
    

    运行结果

  6. 结果分析:从输出可以看出,代理对象对原有的方法进行了增强,模拟添加了打开事务和提交事务的操作,并且也能得出代理对象是被代理类的一个实例,也能看出代理类似继承与被代理类。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值