1. 程式人生 > 其它 >23種設計模式——代理模式

23種設計模式——代理模式

相信大家都知道,有23種代理模式,其中用得比較多的或者是面試中估計問的最多的就是動態代理,但是我們知道,動態代理,靜態代理都只是23種設計模式中的代理模式。好了,話不多說,直接上乾貨。

代理模式

1、動態代理

先建立介面:

/**
 * 功能描述
 *
 * @author yaoqihui
 * @version 2021/7/4
 * @see [相關類/方法]
 * @since [malan-rabbitmq]
 */
public interface UserService {
    void saveUser();
}

寫一個類,實現介面:

import com.sailmalan.malan.service.UserService;
import lombok.extern.slf4j.Slf4j; /** * 功能描述 * * @author yaoqihui * @version 2021/7/4 * @see [相關類/方法] * @since [malan-rabbitmq] */ @Slf4j public class UserServiceImpl implements UserService { @Override public void saveUser() { log.info("動態代理呼叫"); } }

建立代理類(可以重複利用)


import lombok.extern.slf4j.Slf4j;

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

/**
* 動態代理類
*
* @author yaoqihui
* @version 2021/7/4
* @see [相關類/方法]
* @since [malan-rabbitmq]
*/
@Slf4j
public class InvocationHandlerImpl implements InvocationHandler {
private Object target;

public InvocationHandlerImpl(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//method.invoke()方法,真正動態代理的地方,利用的是java的反射,大夥也可以看到包:java.lang.reflect.Method
return method.invoke(target, args);
}
}

動態代理測試類:

import com.sailmalan.malan.service.UserService;
import com.sailmalan.malan.service.impl.UserServiceImpl;

import java.lang.reflect.Proxy;

/**
 * 功能描述:生成UserService,供呼叫---》類似於我們使用springBoot的註解,得到一個userService介面
@Autowired
private UserService userService; * *
@author yaoqihui * @version
2021/7/4 * @see [相關類/方法] * @since [malan-rabbitmq] */
public class TestInvocationHandler {
public static void main(String[] args) {
/************************類似於達到效果的註解:
* @Autowired
* private UserService userService;
* 開始程式碼**************************/
UserService userService = new UserServiceImpl();
InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(userService);
ClassLoader loader = userService.getClass().getClassLoader();
Class<?>[] interfaces = userService.getClass().getInterfaces();
UserService newProxyInstance = (UserService) Proxy.newProxyInstance(loader, interfaces, invocationHandler);
/************************結束程式碼**************************/
newProxyInstance.saveUser();
}
}

2、CGLIB靜態代理

  • CGLIB動態代理和jdk代理一樣,使用反射完成代理,不同的是他可以直接代理類(jdk動態代理不行,他必須目標業務類必須實現介面),CGLIB動態代理底層使用位元組碼技術,CGLIB動態代理不能對 final類進行繼承。(CGLIB動態代理需要匯入jar包)
    //介面
    public interface UserDao {
        void save();
    }
//介面實現類
public class UserDaoImpl implements UserDao {
    public void save() {
        System.out.println("儲存資料方法");
    }
}

代理類:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

//代理主要類
public class CglibProxy implements MethodInterceptor {
    private Object targetObject;
    // 這裡的目標型別為Object,則可以接受任意一種引數作為被代理類,實現了動態代理
    public Object getInstance(Object target) {
        // 設定需要建立子類的類
        this.targetObject = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    //代理實際方法
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("開啟事物");
        Object result = proxy.invoke(targetObject, args);
        System.out.println("關閉事物");
        // 返回代理物件
        return result;
    }
}

測試:

//測試CGLIB動態代理
public class Test {
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        UserDao userDao = (UserDao) cglibProxy.getInstance(new UserDaoImpl());
        userDao.save();
    }
}

2、靜態代理程式碼演示

建立UserDao類:

    //介面類
    public class UserDao{
        public void save() {
            System.out.println("儲存資料方法");
        }
    }

新增代理類

//代理類
public class UserDaoProxy extends UserDao {
    private UserDao userDao;
   //此處是構造器注入
    public UserDaoProxy(UserDao userDao) {
        this.userDao = userDao;
    }

    public void save() {
        System.out.println("開啟事物...");
        userDao.save();
        System.out.println("關閉事物...");
    }

}

下面測試靜態代理的類:

//新增完靜態代理的測試類
public class Test{
    public static void main(String[] args) {
        UserDao userDao = new UserDao();
        UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);
        userDaoProxy.save();
    }
}