什么是代理
从字面意思来说,代理就是代替处理的意思。
从程序层面来说,代理就是代替某个程序,处理某个事情。
静态代理
场景1: 小明需要买基金。
public class Main {
public static void main(String[] args) {
Person xiaoming= new XiaoMing();
boolean isSuccess = xiaoming.buy();//小明去买基金
System.out.println("结果"+(isSuccess?"基金大涨":"被割韭菜"));
}
}
interface Person{
boolean buy();
}
class XiaoMing implements Person{
@Override
public boolean buy() {
System.out.println("我是小明,我要买基金");
return false;
}
}
运行结果
我是小明,我要买基金
结果被割韭菜
场景2: 小明刚买了不久的基金,连跌几天,被割了韭菜,这时候小明找到了一个基金经理,让基金经理帮自己管理基金。
我们新增一个 基金经理的类,并传入一个被代理的人
public class Main {
public static void main(String[] args) {
Person fundManager = new FundManager(new XiaoMing()) ;//小明被基金经理代理了
boolean isSuccess = fundManager.buy();//基金经理去买基金
System.out.println("结果"+(isSuccess?"基金大涨":"被割韭菜"));
}
}
interface Person{
boolean buy();
}
class XiaoMing implements Person{
@Override
public boolean buy() {
System.out.println("我是小明,我要买基金");
return false;
}
}
class FundManager implements Person{
Person person;
FundManager(Person person){
this.person = person;
}
@Override
public boolean buy() {
person.buy();
System.out.println("我是基金经理,我帮我的用户赚钱");
return true;
}
}
运行结果
我是小明,我要买基金
我是基金经理,我帮我的用户赚钱
结果基金大涨
场景3: 小明已经通过基金经理赚了不少钱,他需要卖出一部分,并且开始进行基金定投。
package cn.enncy.scs;
public class Main {
public static void main(String[] args) {
Person fundManager = new FundManager(new XiaoMing()) ;
fundManager.buy();
fundManager.sell();
fundManager.autoInvestment();
}
}
interface Person{
boolean buy();
boolean sell();
boolean autoInvestment();
}
class XiaoMing implements Person{
@Override
public boolean buy() {
System.out.println("我是小明,我要买基金");
return false;
}
@Override
public boolean sell() {
System.out.println("我是小明,我要出售基金");
return false;
}
@Override
public boolean autoInvestment() {
System.out.println("我是小明,我要定投基金");
return false;
}
}
class FundManager implements Person{
Person person;
FundManager(Person person){
this.person = person;
}
@Override
public boolean buy() {
person.buy();
System.out.println("我是基金经理,我帮我的用户赚钱");
return true;
}
@Override
public boolean sell() {
return person.sell();
}
@Override
public boolean autoInvestment() {
return person.autoInvestment();
}
}
结果
我是小明,我要买基金
我是基金经理,我帮我的用户赚钱
我是小明,我要出售基金
我是小明,我要定投基金
我们可以看到,其实定投
和出售
,根本不需要经过基金经理进行代理,自己进行这个操作就行了,所以代码非常冗余,如果不经过基金经理又会被割韭菜。
那要怎么实现,当买基金的时候让基金经理代理,不需要买基金的时候,其他操作自己执行
?
这时候,动态代理
的优势就体现出来了
动态代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
PersonProxy personProxy = new PersonProxy(new XiaoMing());
Person fundManager = personProxy.createProxy();
fundManager.buy();
fundManager.sell();
fundManager.autoInvestment();
}
}
interface Person{
boolean buy();
boolean sell();
boolean autoInvestment();
}
class XiaoMing implements Person{
@Override
public boolean buy() {
System.out.println("我是小明,我要买基金");
return false;
}
@Override
public boolean sell() {
System.out.println("我是小明,我要出售基金");
return false;
}
@Override
public boolean autoInvestment() {
System.out.println("我是小明,我要定投基金");
return false;
}
}
class PersonProxy implements InvocationHandler {
Object target;
PersonProxy(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
System.out.println("方法"+method.getName()+"已经被我代理");
if("buy".equals(method.getName())){
method.invoke(target, args);
System.out.println("我是代理,我将帮你买基金");
}
return true;
}
public <T> T createProxy(){
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
结果
方法buy已经被我代理
我是小明,我要买基金
我是代理,我将帮你买基金
方法sell已经被我代理
方法autoInvestment已经被我代理
target
: 被代理的对象InvocationHandler
: jdk 动态代理类invoke
: 由jdk动态代理的方法,proxy
: jdk 代理类method
: 当前被代理类的方法args
当前被代理类的方法参数
Proxy.newProxyInstance
: 代理类的实例化方法target.getClass().getClassLoader()
: 目标类的 ClassLoadertarget.getClass().getInterfaces()
: 目标类的 interfacesthis
: 代理类对象
动态代理-代理接口
想要实例化接口,但是又不创建实例类的骚操作,具体实现方法完全通过动态代理自由实现。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
Person personProxy = PersonProxy.createProxy(Person.class);
personProxy.say();
}
}
interface Person{
void say();
}
class PersonProxy implements InvocationHandler {
Class target;
PersonProxy(Class target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我就是"+method.getName()+"函数的方法体!");
return null;
}
public static <T> T createProxy(Class clazz){
return (T) Proxy.newProxyInstance(clazz.getClassLoader(),new Class[]{clazz}, new PersonProxy(clazz));
}
}
结果
我就是say函数的方法体!
是不是非常 amazing !!!
根本没有任何的实例类!但是同样可以调用方法!可以调侃的说接口自己实现了自己 😂😂😂
- 这里要注意不能使用
method.invoke(target, args);
因为你根本没有任何实例类,和方法体,你调用这句话只会报错。 Proxy.newProxyInstance
的参数完全不同,第二个参数
是要传入 对象的interfaces
接口,而new Class[]{clazz}
则是吧 clazz 当做接口参数传递。
总结:
代理的好处
1.代理类不影响原先代码执行,面向切面编程,典型的AOP。
2.代理类可以重新返回一个新的值,作为原先的函数的值。
动态代理的应用
- 更精确的日志系统,可以使用包扫描,将每个类每个属性,方法全部进行动态代理,这样,从程序开始到结束,所有函数调用等细节都能被打印出来。
- mybatis 的核心,注解开发,各种SQL语句注解,当调用的时候,通过动态代理,获取被代理方法上注解中的sql语句,然后执行。可以用动态代理做一个简易的 mybatis 试试。
- 当你遇到一个很复杂的需求,不得不修改别人的代码,但这往往会导致不可预计的bug的时候,通过动态代理,对返回值进行处理即可。这样既避免了修改原有代码,又完成了新的需求。
还有很多应用这里不一一列举了。
静态代理的缺点
- 当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式:只维护一个代理类,由这个代理类实现多个接口,但是这样就
导致代理类过于庞大
新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类
- 当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护。