Java动态代理

Java动态代理

一、动态代理:介绍、准备

在这里插入图片描述
2.
在这里插入图片描述
3.
在这里插入图片描述
4.
在这里插入图片描述

二、动态代理:创建代理、工作流程演示

例子1:包含四个文件BigStar.java、Star.java、ProxyUtil.java、Test.java

BigStar.java代码:

package d4_proxy;

/*
 * 大明星
 */
public class BigStar implements Star{
	private String name;
	
	public BigStar(String name) {
		this.name = name;
	}
	
	public String sing(String name) {
		System.out.println(this.name + "正在唱:" + name);
		return "谢谢!谢谢!";
	}
	
	public void dance() {
		System.out.println(this.name + "正在优美的跳舞~~");
	}

}

Star.java代码:

package d4_proxy;

/*
 * Star接口
 */
public interface Star {
	String sing(String name);
	void dance();

}

ProxyUtil.java代码:

package d4_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/*
 * 中介公司
 */
public class ProxyUtil {
	public static Star createProxy(BigStar bigstar) {
		/*newProxyInstance(ClassLoader loader,
                Class<?>[] interfaces,
                InvocationHandler h)
                参数1:用于指定一个类加载器,用此加载器去加载生成的代理类
                该参数写法一般是固定的,都是用当前类的类加载器,此处即为ProxyUtil.class.getClassLoader()
                参数2:用于指定生成的代理长什么样子,也就是有哪些方法
                该例中被代理类BigStar只有一个接口,即通过Star接口来告诉生成的代理类应该有哪些方法,
                此处Class<?>[] interfaces为数组,因为被代理类有时有多个接口,
                由于BigStar只有Star一个接口,因此只需要把这一个接口包装成数组就行了,此处即为new Class[]{Star.class}
                参数3:用来指定生成的代理对象要干什么事情
                InvocationHandler是一个接口,接口不能直接创建对象,
                因此我们一般做法为new一个该接口命名的内部类对象(即该接口的匿名实例)来指定代理对象干什么事情,
                此处即为
                new InvocationHandler() {
                	@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						return null;
					}			
				}
                */
		
		Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
				new Class[]{Star.class}, new InvocationHandler() {
				/*
				 * 代理干什么事情实际是由invoke方法决定的
				 * invoke方法是一个回调方法
				 * 
				 * 假设代理写好后,
				 * 我们在主程序(Test.java)会写这样的代码:
				 * Star starProxy = ProxyUtil.createProxy(s); //s为BigStar的实例
				 * 这样就得到了一个代理对象
				 * 然后我们会调用代理对象的sing方法和dance方法
				 * starProxy.sing("好日子")和starProxy.dance()
				 * 当我们调用代理对象的sing方法和dance方法时,sing和dance方法会调用此处的invoke方法
				 * invoke方法有三个参数 invoke(Object proxy, Method method, Object[] args)
				 * sing和dance方法调用invoke方法时也需要传入这三个参数
				 * 第一个参数:Java会把当前代理对象(starProxy)当作一个Object对象传给invoke方法的Object proxy参数
				 * 			  也就是说我们可以通过invoke方法的Object proxy参数获取当前的代理对象starProxy
				 * 第二个参数:它会把当前调用的方法当作一个method传进来,这个method具体是谁,由外面的调用者决定,如果
				 * 			  外面是sing是在调用invoke,那此时method就代表sing方法,如果外面dance在调用invoke,那
				 * 			  此时method就代表dance方法
				 * 第三个参数:Object[] args,它会把方法的参数通过Object[]数组传进来,比如starProxy.sing("好日子")中,
				 * 			  将"好日子"包装成Object[]数组通过Object[] args参数传进来,
				 */
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						//代理对象要干的事情,会在这里写代码指定
						
						//假设我们现在的业务需求是唱歌,要提前准备话筒,收钱20万;跳舞,要提前准备场地,收钱1000万
						//根据业务需求,我们需要在invoke方法里,用if来询问当前method代表方法名是不是equals("sing"),
						//如果是,说明当前正在代理唱歌方法,那我们就需要先"准备话筒,收钱20万",然后准备让BigStar对象实例来唱歌,
						//调用method.invoke()方法,传入BigStar对象对应参数bigstar以及唱哪首歌对应的参数args,
						//method.invoke(bigstar, args)即相当于bigstar.sing(args)
						if(method.getName().equals("sing")){
							System.out.println("准备话筒,收钱20万");
							//method.invoke(bigstar, args);
							//因为此时method.invoke(bigstar, args);方法有返回值,返回“谢谢!”“谢谢!”,因此要加return
							return method.invoke(bigstar, args);
						}
						else if(method.getName().equals("dance")){
							System.out.println("准备话筒,收钱1000万");
							//把该方法结果也返回出去,虽然没有返回值
							return method.invoke(bigstar, args);
						}
						else {
							//假设其他方法不需要代理,直接找bigstar
							return method.invoke(bigstar, args);
						}
						/*
						 * 
						 * 抽出共同需要执行的语句,以上代码可以简化为
						 * if(method.getName().equals("sing")){
						 *     System.out.println("准备话筒,收钱20万");
						 * }
						 * else if(method.getName().equals("dance")){
						 *     System.out.println("准备话筒,收钱1000万");
						 * }
						 * return method.invoke(bigstar, args);
						 * 
						 * 
						 */
					}
				});
		return starProxy;
	}

}

Test.java代码:

package d4_proxy;

/*
 * 主程序
 */
public class Test {
	public static void main(String[] args) {
		BigStar s = new BigStar("杨超越"); //创建BigStar实例
		Star starProxy = ProxyUtil.createProxy(s); //为s创建代理对象,并赋值给starProxy
		
		//调用代理对象的sing方法唱一首歌
		//starProxy.sing("好日子");
		//由于该方法有返回值,因此需要定义一个变量(String rs)来接收返回值
		String rs = starProxy.sing("好日子");
		System.out.println(rs);
		
		starProxy.dance();
	}

}

例子2:包含一个文件Main.java

Main.java代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method);
                if (method.getName().equals("morning")) {
                    System.out.println("Good morning, " + args[0]);
                }
                return null;
            }
        };
        Hello hello = (Hello) Proxy.newProxyInstance(
            Hello.class.getClassLoader(), // 传入ClassLoader
            new Class[] { Hello.class }, // 传入要实现的接口
            handler); // 传入处理调用方法的InvocationHandler
        hello.morning("Bob");
    }
}

interface Hello {
    void morning(String name);
}
三、动态代理:实际应用、好处

将共同需要实现的功能放到代理,并根据不同需求使用代理实现

例子:包含四个文件UserServiceImpl.java、UserService.java、ProxyUtil.java、Test.java

UserServiceImpl.java代码:

package d5_proxy2;

/*
 * 用户业务实现类(面向接口编程)
 */
public class UserServiceImpl implements UserService{
	@Override
	public void login(String loginName, String passWord) throws Exception {
		//long startTime = System.currentTimeMillis();
		
		//模拟登录用户
		if("admin".equals(loginName) && "123456".equals(passWord)) {
			System.out.println("您登录成功,欢迎光临本系统~");
		} else {
			System.out.println("您登录失败,用户名或密码错误~");
		}
		//模拟该业务耗时1000ms
		Thread.sleep(1000);
		
		//long endTime = System.currentTimeMillis();
		//System.out.println("login方法执行耗时:" + (endTime - startTime)/1000.0 + "s");
	}
	
	@Override
	public void deleteUsers() throws Exception {
		//long startTime = System.currentTimeMillis();
		
		//模拟删除用户
		System.out.println("成功删除了一万个用户~");
		//模拟该业务耗时1500ms
		Thread.sleep(1500);
		
		//long endTime = System.currentTimeMillis();
		//System.out.println("deleteUsers方法执行耗时:" + (endTime - startTime)/1000.0 + "s");
	}
	
	@Override
	public String[] selectUsers() throws Exception {
		//long startTime = System.currentTimeMillis();
		
		//模拟查询用户
		System.out.println("查询出了3个用户");
		String[] names = {"张全蛋", "李二狗", "牛爱花"};
		//模拟该业务耗时500ms
		Thread.sleep(500);
		
		//long endTime = System.currentTimeMillis();
		//System.out.println("selectUsers方法执行耗时:" + (endTime - startTime)/1000.0 + "s");
		return names;
	}

}

UserService.java代码:

package d5_proxy2;

/*
 * 用户业务接口
 */
public interface UserService {
	//登录功能
	void login(String loginName,String password) throws Exception;
	//删除用户
	void deleteUsers() throws Exception;
	//查询用户,返回数组的形式
	String[] selectUsers() throws Exception;

}

ProxyUtil.java代码:

package d5_proxy2;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/*
 * 代理类,将统计方法耗时的代码放到代理类中
 */
public class ProxyUtil {
	public static UserService createProxy(UserService userservice) {
		UserService userServiceProxy = (UserService) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
				new Class[] {UserService.class}, new InvocationHandler() {

					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						// TODO Auto-generated method stub
						if(method.getName().equals("login") || method.getName().equals("deleteUsers") || 
								method.getName().equals("selectUsers")) {
							long startTime = System.currentTimeMillis();
							
							Object rs = method.invoke(userservice, args);
							
							long endTime = System.currentTimeMillis();
							System.out.println(method.getName() + "方法执行耗时:" + (endTime - startTime)/1000.0 + "s");
							
							return rs;
						} else {
							//调用其他方法时则不统计时间,直接调用方法
							Object rs = method.invoke(userservice, args);
							//并把方法的结果返回出去
							return rs;
						}
					}
			
		});
		return userServiceProxy;
	}

}

Test.java代码:

package d5_proxy2;

import java.util.Arrays;

public class Test {
	public static void main(String[] args) throws Exception{
		//1.创建用户业务对象
		//直接执行,没有耗时统计
		//UserService userService = new UserServiceImpl();
		//使用代理后,有耗时统计功能
		UserService userService = ProxyUtil.createProxy(new UserServiceImpl());
		
		//2.调用用户业务的功能
		userService.login("admin", "123456");
		System.out.println("-------------------------------");
		
		userService.deleteUsers();
		System.out.println("-------------------------------");
		
		String[] names = userService.selectUsers();
		System.out.println("查询到的用户是:" + Arrays.toString(names));
		System.out.println("-------------------------------");
	}

}

【黑马磊哥】Java动态代理深入剖析,真正搞懂Java核心设计模式:代理设计模式,
视频地址:https://www.bilibili.com/video/BV1ue411N7GX/?spm_id_from=333.337.search-card.all.click

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值