Spring框架簡介⑦

Milky-way發表於2018-08-07

接下來進入Spring的另一核心AOP(aspect oriented programming)

面向切面程式設計, 通過預編譯的方式在執行期通過動態代理實現的一種技術, AOP是OOP的延續, 利用AOP可以實現業務和切面的邏輯分離. 降低耦合度, 程式的重用性提高.

1 JDK動態代理

JDK動態代理的目標是介面實現類的形式

直接上程式碼:

代理類:

package com.rl.spring.proxy;

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

public class JDKProxy implements InvocationHandler {

    private Object targetObj;

    /**
     * 第一個引數: 獲得目標物件的類的載入器 
     * 第二個引數: 獲得目標物件的介面 
     * 第三個引數: 設定回撥物件, 當前代理物件(也就是UserServiceImpl)的方法(save方法)被呼叫時, 會委派該引數去呼叫invoke
                   需要傳入InvocationHandler的子類, 這裡用this指代JDKProxy
     * @return
     */
    public Object createProxyInstance(Object targetObj) {
        this.targetObj = targetObj;
        return Proxy.newProxyInstance(this.targetObj.getClass().getClassLoader(),
                this.targetObj.getClass().getInterfaces(), this);
    }

    /**
     * proxy: 代理類 
     * Method: 要呼叫的業務方法 
     * Object[]: 呼叫的業務方法的引數
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 獲得目標物件的get方法
        Method getMeth = this.targetObj.getClass().getMethod("getUser", null);
        // 通過反射來呼叫getUser
        Object user = getMeth.invoke(targetObj, null);
        Object obj = null;
        if (user != null) {
            // 業務方法返回的值
            obj = method.invoke(this.targetObj, args);
        } else {
            System.out.println("您還沒有登入");
        }
        return obj;
    }
}

測試類:

package com.rl.spring.test;

import org.junit.Test;

import com.rl.spring.model.User;
import com.rl.spring.proxy.JDKProxy;
import com.rl.spring.service.UserService;
import com.rl.spring.service.impl.UserServiceImpl;

public class TestSpring {
	
    @Test
    public void Test() {
        UserServiceImpl ui = new UserServiceImpl();
        ui.setUser(new User());
        //通過業務介面來接收代理物件
        UserService userService = (UserService) new JDKProxy().createProxyInstance(ui);
        System.out.println(userService.getClass());
        userService.save();
    }
}

UserServiceImpl類

package com.rl.spring.service.impl;

import com.rl.spring.model.User;
import com.rl.spring.service.UserService;
public class UserServiceImpl implements UserService {

    private User user;
    
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public void save() {
        System.out.println("儲存使用者...");
    }

    @Override
    public void update() {
        System.out.println("修改使用者...");
    }
}

輸出:

儲存使用者.../ 如果在測試程式碼中沒有new User()的話, 則提示"您還沒有登入!"

小總結:

代理類提供了一種切面針對目標物件的一種攔截並做相應處理, 在User類中並沒有邏輯處理, 但卻能夠實現一種攔截判斷是否有登入的效果, 這就是代理類的功能所在.

 

2 CGLIB動態代理

CGLIB可以對普通類做動態代理, 前提是目標類不能為final, 類裡面的方法也不能為final

直接上程式碼:

代理類:

package com.rl.spring.proxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class CGLIBProxy implements MethodInterceptor {

    private Object targetObj;
    
    public Object createProxyInstance(Object targetObj) {
        this.targetObj = targetObj;
        Enhancer en = new Enhancer();
        en.setSuperclass(this.targetObj.getClass());
        en.setCallback(this);
        return en.create();
    }

    @Override
    public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
        Method getMeth = this.targetObj.getClass().getMethod("getUser", null);
        Object user = getMeth.invoke(targetObj, null);
        Object obj = null;
        if(user != null) {
            obj = method.invoke(this.targetObj, arg2);
        }else {
            System.out.println("您還沒有登入!");
        }
        return obj;
    }
}

測試程式碼:

package com.rl.spring.test;

import org.junit.Test;

import com.rl.spring.model.User;
import com.rl.spring.proxy.CGLIBProxy;
import com.rl.spring.proxy.JDKProxy;
import com.rl.spring.service.UserService;
import com.rl.spring.service.impl.UserServiceImpl;

public class TestSpring {
	
    
    @Test
    public void Test1() {
        UserServiceImpl ui = new UserServiceImpl();
        ui.setUser(new User());
        UserServiceImpl userServiceImpl = (UserServiceImpl) new CGLIBProxy().createProxyInstance(ui);
        System.out.println(userServiceImpl.getClass());
        userServiceImpl.save();
    }
}

目標物件(UserServiceImpl同上, 不列出來了), 該類可作為實現類, 也可作為普通類 CGLIB都可以對其做動態代理

 

 

 

 

 

相關文章