天天看点

Spring(八)jdk动态代理(AOP简单实现)

说明

jdk动态代理就是对“装饰者”设计模式的简化。使用前提:必须要有接口

编写过程:

1.目标类:接口+实现类

2.切面类:用于存放通知。

3.工厂类:编写工厂生成代理

4.测试

UserService 接口 三个方法

public interface UserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}      

UserService 实现类,实现了三个方法

public class UserServiceImpl implements UserService

    @Override
    public void addUser() {
        System.out.println("UserServiceDaoImpl addUser");
    }

    @Override
    public void updateUser() {
        System.out.println("UserServiceDaoImpl updateUser");
    }

    @Override
    public void deleteUser() {
        System.out.println("UserServiceDaoImpl deleteUser");
    }

}      

切面类,共两个方法,before和end。希望在目标类的方法运行前后各调用一次。

public class MyAspect {
    public void before(){
        System.out.println("before");

    }
    public void after(){
        System.out.println("after");
    }
}         

工厂类,用于生成代理。

其中代理类的作用就是将目标类(切入点)和切面类(通知)结合。

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

public class MyProxyFactory
    public static Object createUserService() {
        //目标类
        final UserService userServiceDao = new UserServiceImpl();
        //切面类
        final MyAspect myAspect = new MyAspect();
        //代理类
        Object proxy = Proxy.newProxyInstance(MyProxyFactory.class
                .getClassLoader(), userServiceDao.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method,
                            Object[] args) throws Throwable {
                        Object obj = null;
                        //前方法
                        myAspect.before();
                        //执行目标类的方法
                        obj = method.invoke(userServiceDao, args);
                        //后方法
                        myAspect.after();
                        return obj;
                    }
                });
        return      

其中Proxy.newProxyInstance有三个参数。

  • arg1:loader,类加载器,动态代理类,运行时创建,任何类都需要类加载器加载到内存。一般使用当前类.class.getClassLoader();也可以使用目标实例.getClass().getClassLoader()
  • arg2:代理类要实现的所有接口。目标类例.getClass().getInterfaces();
  • arg3:InvocationHandler处理类,接口必须进行实现。一般采用匿名内部实现。提供的invoke方法。代理类的每一个方法执行都会调用一次invoke。invoke也有三个参数(Object proxy:代理对象, Method method:代理对象当前执行的方法,Object[] args:当前执行方法的参数)。我们可以通过method.getName来为不同的方法实现不同的功能。

测试类

public class Test {
    @org.junit.Test
    public void testProxy(){
        UserService userService=(UserService) MyProxyFactory.createUserService();
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }
}      

运行结果

Spring(八)jdk动态代理(AOP简单实现)

我们可以看到虽然我们调用的UserService对象,但是在每个方法执行的前后都有输出before和after。所以我们使用工厂类实现了jdk动态代理。

我们其实可以这样理解jdk动态代理。

在底层我们在调用代理类的方法时,它会执行invoke方法。

代理类本身没有什么功能,它只是把所有的功能组合在一起。

代理类
addUser(){
    invoke(this,addUser,[]);
}
updateUser(){
    invoke(this,updateUser,[]);
}
deleteUser(){
    invoke(this,deleteUser,[]);
}      

你看懂了吗?

上面说了 我们可以通过method.getName来为特定的方法实现特定的功能。那么我们只为addUser方法执行before和after方法。

我们修改代理类的invoke方法

@Override
                    public Object invoke(Object proxy, Method method,
                            Object[] args) throws Throwable {
                        Object obj = null;
                        if("addUser".equals(method.getName())){
                            //前方法
                            myAspect.before();
                            //执行目标类的方法
                            obj = method.invoke(userServiceDao, args);
                            //后方法
                            myAspect.after();
                        }else{
                            obj = method.invoke(userServiceDao, args);
                        }
                        return