手寫@Async註解

項目目錄結構

項目下載

https://github.com/cbeann/Demoo/tree/master/async-demo

實踐

pom

  <!-- https://mvnrepository.com/artifact/cglib/cglib -->
        <!--cglib依賴-->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>

自定義標註註解

沒有方法參數的註解成爲標註註解

//Async註解
@Target(ElementType.METHOD)//方法註解
@Retention(RetentionPolicy.RUNTIME)//運行時註解
public @interface MyAsyncInterface {
}

自定義執行器

package com.imooc.demo.executor;

import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.concurrent.FutureTask;

public class MyExecutor {

    /*
    動態代理的異步執行方法,參數就是 invoke(Object proxy, Method method, Object[] args)
     */
    public static void submit(Object object, Method method, Object[] args) throws Exception {
        //封裝成callable接口
        MyDyCallable myCallable = new MyDyCallable(object, method, args);
        FutureTask futureTask = new FutureTask(myCallable);
        //運行線程
        new Thread(futureTask).start();


    }

    /*
    cglib的異步執行方法intercept(Object object, Method method, Object[] args, MethodProxy proxy) 
     */
    public static void submit(Object object, Method method, Object[] args, MethodProxy proxy) throws Exception {
        //封裝成callable接口
        MyCglibCallable myCglibCallable = new MyCglibCallable(object, method, args, proxy);
        FutureTask futureTask = new FutureTask(myCglibCallable);
        //運行線程
        new Thread(futureTask).start();


    }

}



 

實現動態代理的異步執行

IEmailService接口

public interface IEmailService {


    public void sendEmail();

    public void speak();
}

IEmailService接口實現類

其中帶有MyAsyncInterface我們要使其成爲異步方法

package com.imooc.demo.dyproxy;

import com.imooc.demo.myinterface.MyAsyncInterface;



public class EmailService implements IEmailService {

    @MyAsyncInterface
    @Override
    public void sendEmail() {
        System.out.println("開始發送email---------->睡10秒");

        try {
            //處理業務10毫秒
            Thread.sleep(1000 * 2);
        } catch (Exception e) {

        }

        System.out.println("結束髮發送email<----------");
    }

    public void speak() {
        System.out.println("-----EmailService------");
    }
}

 MyAsyncHandler (動態代理知識)

package com.imooc.demo.dyproxy;

import com.imooc.demo.myinterface.MyAsyncInterface;
import com.imooc.demo.executor.MyExecutor;

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


public class MyAsyncHandler implements InvocationHandler {

    //目標對象
    private Object target;

    //傳入代碼目標對象
    public MyAsyncHandler(Object object) {
        this.target = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable, Exception {

        //method參數是接口的方法,上面是不帶@MyAsyncInterface的,我們一般是定義在接口實現類上,所以我們通過接口的method獲取target(實現類)的方法,從而獲取自定義註解信息
        MyAsyncInterface annotation = target.getClass().getMethod(method.getName(), method.getParameterTypes()).getAnnotation(MyAsyncInterface.class);


        if (null != annotation) {
            //如果該方法有自定義異步註解,啓動線程跑
            MyExecutor.submit(target, method, args);
        } else {
            //如果該方法沒有自定義異步註解,同步執行
            Object invoke = method.invoke(target, args);
        }


        //如果有結果返回,如果沒有就不返回
        return null;
    }
}

MyDyCallable:實現Callable接口(多線程知識)

目的:如果方法時異步,將參數傳入callable,並且啓動線程執行

package com.imooc.demo.executor;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;


public class MyDyCallable implements Callable<Object> {

    private Object target;
    private Method method;
    private Object[] args;

    public MyDyCallable(Object object, Method method, Object[] args) {
        this.target = object;
        this.method = method;
        this.args = args;

    }

    @Override
    public Object call() throws Exception {
        Object result = method.invoke(target, args);
        return result;
    }
}

ProxyStart:測試類

package com.imooc.app;

import com.imooc.demo.dyproxy.EmailService;
import com.imooc.demo.dyproxy.IEmailService;
import com.imooc.demo.dyproxy.MyAsyncHandler;

import java.lang.reflect.Proxy;


public class ProxyStart {
    public static void main(String[] args) {

        IEmailService emailService = new EmailService();
        MyAsyncHandler asyncHandler = new MyAsyncHandler(emailService);
        Class cls = emailService.getClass();

        //創建動態代理對象
        IEmailService newProxyInstance = (IEmailService) Proxy.newProxyInstance(
                cls.getClassLoader(), cls.getInterfaces(), asyncHandler);

        //此方法時異步
        newProxyInstance.sendEmail();
        //此方法時同步
        newProxyInstance.speak();
        
//        執行結果如下:        
//        -----EmailService------      newProxyInstance.speak()方法
//        開始發送email---------->睡10秒    newProxyInstance.sendEmail();方法
//        結束髮發送email<----------

    }
}

 

實現cglib的異步執行

MQService 

方法setMessage方法,我們使其成爲異步方法

package com.imooc.demo.cglibproxy;

import com.imooc.demo.myinterface.MyAsyncInterface;


public class MQService {

    @MyAsyncInterface
    public void setMessage(String messgae) {

        System.out.println("開始發送MQmessage--------->睡3秒");

        try {
            Thread.sleep(1000 * 3);
        } catch (Exception e) {

        }
        System.out.println("結束髮送MQmessage<-------------");

    }
}

CGlibProxy (動態代理cglib知識)

package com.imooc.demo.cglibproxy;

import com.imooc.demo.executor.MyExecutor;
import com.imooc.demo.myinterface.MyAsyncInterface;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;


public class CGlibProxy implements MethodInterceptor {


    private Enhancer enhancer = new Enhancer();


    public Object getProxy(Class clz) {
        enhancer.setSuperclass(clz);
        enhancer.setCallback(this);
        return enhancer.create();

    }

    /**
     * @param object 目標類的實例
     * @param method 目標方法的反射對象
     * @param args   目標方法的參數
     * @param proxy  代理類的實例
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {


        if (method.getAnnotation(MyAsyncInterface.class) != null) {
            MyExecutor.submit(object, method, args, proxy);
        } else {
            proxy.invokeSuper(object, args);
        }


        return null;
    }
}

MyCglibCallable (多線程知識)

package com.imooc.demo.executor;

import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;


public class MyCglibCallable implements Callable {

    private Object object;
    private Method method;
    private Object[] args;
    private MethodProxy proxy;


    //參數是intercept(Object object, Method method, Object[] args, MethodProxy proxy) 
    public MyCglibCallable(Object object, Method method, Object[] args, MethodProxy proxy) {
        this.object = object;
        this.args = args;
        this.method = method;
        this.proxy = proxy;

    }


    @Override
    public Object call() {
        try {
            proxy.invokeSuper(object, args);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return null;
    }
}

CGlibStart 測試類

package com.imooc.app;

import com.imooc.demo.cglibproxy.CGlibProxy;
import com.imooc.demo.cglibproxy.MQService;

public class CGlibStart {
    public static void main(String[] args) {

//        MQService mqService = new MQService();
//        mqService.setMessage("123123");

        CGlibProxy cGlibProxy = new CGlibProxy();
        MQService proxy = (MQService) cGlibProxy.getProxy(MQService.class);
        proxy.setMessage("123");
        System.out.println("-----------------------");
        
        
//        執行結果
//        -----------------------             System.out.println("-----------------------");
//        開始發送MQmessage--------->睡3秒     proxy.setMessage("123");
//        結束髮送MQmessage<-------------
    }
}

 

總結

1)需要了解動態代理、多線程知識

2)上面都是按照方法沒有返回結果算的,實際情況下是很多是有結果的

3)多線程中Callable是有返回結果的

 

 

 

 

 

 

發佈了96 篇原創文章 · 獲贊 115 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章