动态代理之jdk代理-简单实现

动态代理有种实现方式:一个是jdk提供的,一个是cglib提供的。

动态代理三要素:proxy代理类、InvocationHandler接口、Invoke方法

1. TransactionManager.java

	package proxy.jdk;
	 
	import org.springframework.stereotype.Component;
	 
	@Component
	public class TransactionManager {
		public void begin(){
			System.out.println("事务开启");
		}
		public void commit(){
			System.out.println("事务提交");
		}
		public void rollback(){
			System.out.println("事务回滚");
		}
	}

2. UserDao.java

	package proxy.jdk.dao;
	 
	public interface UserDao {
		public void addUser();
		public void updateUser();
	}

3. UserDaoImpl.java

	package proxy.jdk.dao;
	 
	import org.springframework.stereotype.Repository;
	 
	@Repository(value="userDao")
	public class UserDaoImpl implements UserDao{
	 
		public void addUser() {
			System.out.println("新增用户");
		}
	 
		public void updateUser() {
			System.out.println("修改用户");
		}
	 
	}

4. UserService.java

	package proxy.jdk.service;
	 
	public interface UserService {
		public void addUser();
		public void updateUser();
	}

5. UserServiceImpl.java

	package proxy.jdk.service;
	 
	import org.springframework.beans.factory.annotation.Autowired;
	import org.springframework.stereotype.Service;
	import proxy.jdk.dao.UserDao;
	 
	@Service(value="userService")
	public class UserServiceImpl implements UserService{
		@Autowired
		private UserDao userDao;
		public void addUser() {
			userDao.addUser();
		}
	 
		public void updateUser() {
			userDao.updateUser();
		}
	 
	}

6. DynamicProxy.java

            步骤:

  1. 写一个获取代理方法,把被代理对象和事务对象作为参数传入
  2. 通过反射创建实例 Proxy.newProxyInstance,参数:类加载器、接口
  3. 匿名内部类new InvocationHandler,参数:代理对象、方法,参数
  4. 回调 result = method.invoke,参数:目标对象、参数
	package proxy.jdk;
	 
	import java.lang.reflect.InvocationHandler;
	import java.lang.reflect.Method;
	import java.lang.reflect.Proxy;
	 
	public class DynamicProxy {
		// 创建代理对象,传入真实对象和事务对象
		public static Object getProxy(final Object target, final TransactionManager tx) {
		
			Object proxy = Proxy.newProxyInstance(
					target.getClass().getClassLoader(), 
					target.getClass().getInterfaces(),
					// 采用匿名内部类方式,参数必须final
					new InvocationHandler() {
						// 代理对象,真实对象的方法,真实对象的参数
						public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
							Object result = null;
							Long beginTime = System.currentTimeMillis();
	 
							try {
								tx.begin();
								// 通过反射调用真实对象的方法
								result = method.invoke(target, args);
								tx.commit();
							} catch (Exception e) {
								tx.rollback(); // 异常后返回null
							}
	 
							Long endTime = System.currentTimeMillis();
							System.out.println("执行时间:" + (endTime - beginTime) + " 毫秒");
	 
							// 必须设置返回值,否则下面过程就无法获取到执行结果
							return result;
						}
					});
			return proxy;
		}
	}

7. applicationContext.xml

	<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:context="http://www.springframework.org/schema/context"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-3.2.xsd    
	">
		<context:component-scan base-package="proxy.jdk.dao,proxy.jdk.service.UserService,proxy.jdk.service,proxy.jdk"/>
	</beans>

8. 测试类

	package proxy.jdk;
	 
	import org.junit.Test;
	import org.springframework.context.ApplicationContext;
	import org.springframework.context.support.ClassPathXmlApplicationContext;
	import proxy.jdk.service.UserService;
	 
	public class TestSpring {
		@Test
		public void test(){
			//启动spring容器
			ApplicationContext context = new ClassPathXmlApplicationContext("proxy/jdk/applicationContext.xml");
			
			UserService target = (UserService) context.getBean("userService");
			
			TransactionManager tx = (TransactionManager) context.getBean("transactionManager");
			
			UserService proxy = (UserService)DynamicProxy.getProxy(target, tx);
			
			System.out.println(proxy.getClass());
			
			proxy.addUser();
		}
	}

9. 执行结果

class com.sun.proxy.$Proxy7    //代理对象

事务开启

新增用户

事务提交

执行时间:0 毫秒    //没有真正的业务所以执行很快

    Proxy代理类

Proxy是JDK中用来创建代理对象的类,其中使用最多的是newProxyInstance方法来创建代理对象。

public static Object newProxyInstance(
	ClassLoader loader,        //由哪个类加载器加载生成代理对象
	Classs<?>[] interfaces,    //接口对象数组,必须传入目标对象的接口
	InvocationHandler h        //表示一个invocationHandler对象,当代理对象执行方法时,会调用改InvocatonHandler对象
) throws IllegalArgumentException

注意:由于实现类没有接口,会导致执行报错!如:PersonServiceImpl proxyImpl = (PersonServiceImpl)DynamicProxy.getProxy(impl, tx);

java.lang.ClassCastException: com.sun.proxy.$Proxy8 cannot be cast to proxy.jdk.service.PersonServiceImpl
	at proxy.jdk.TestSpring.test(TestSpring.java:27)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值