反射、动态代理与Spring的AOP

反射、动态代理与Spring的AOP

反射

看到一篇写的很好的文章
[java反射详解]: http://t.csdn.cn/wGVqm

代理模式

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。

在这里插入图片描述

程序为什么需要代理,代理长什么样?

1、对象如果嫌身上干的事情太多,可以通过代理来转移部分职责

2、对象有什么方法想被代理,代理就必须要有对应的方法

(一)静态代理

静态代理:由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口、被代理类、代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。

(二)动态代理

代理类在程序运行时创建的代理方式被成为动态代理。

我们上面静态代理的例子中,代理类(studentProxy)是自己定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。

实体类

public class BigStar implements Star{

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String sing(String name) {
        System.out.println(this.name + "正在唱:" + name);
        return "谢谢大家!!!";
    }

    public void dance() {
        System.out.println(this.name + "正在跳舞~~~");
    }

    public BigStar(String name) {
        this.name = name;
    }
}

代理接口

public interface Star {
    String sing(String name);
    void dance();
}

代理类

public class ProxyUtil {
    public static Star createProxy(BigStar bigStar) {
               /*
                newProxyInstance(ClassLoader loader, 参数一 用于指定一个类加载器
                Class<?>[] interfaces, 参数二 指定生成的代理是什么样子,也就是需要哪些方法
                InvocationHandler h) 参数三 用来指定生成的代理对象要干什么事情
                */
        Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class},
                (proxy, method, args) -> {
                    if (method.getName().equals("sing")) {
                        System.out.println("准备话筒,收钱20万!");
                    } else if (method.getName().equals("dance")){
                        System.out.println("准备场地,收钱2000万");
                    }
                    return method.invoke(bigStar, args);
                });
        return starProxy;
    }
}

实现类

public class Test {
    public static void main(String[] args) {
        BigStar s = new BigStar("刘德华");
        Star starProxy = ProxyUtil.createProxy(s);
        String rs = starProxy.sing("恭喜发财");
        System.out.println(rs);

        starProxy.dance();
    }
}

   /*    
	准备话筒,收钱20万!
    刘德华正在唱:恭喜发财
    谢谢大家!!!
    准备场地,收钱2000万
    刘德华正在跳舞~~~
   */

练习(动态代理)

**场景:**某系统有一个用户管理类,包含用户登录,删除用户,查询用户等功能,系统要求统
计每个功能的执行耗时情况,以便后期观察程序性能。

接口(需要实现的方法)

public interface UserService {
    void login(String name,String password) throws Exception;

    void deleteUsers() throws Exception;

    String[] selectUsers() throws Exception;
}

接口实现类

public class UserServiceImpl implements UserService{
    @Override
    public void login(String name, String password) throws Exception{
        if ("admin".equals(name) && "123456".equals(password)) {
            System.out.println("登录成功,欢迎进入本系统");
        } else {
            System.out.println("登陆失败,用户名或密码错误!");
        }
        Thread.sleep(1000);
    }

    @Override
    public void deleteUsers() throws Exception {
        System.out.println("成功删除了1万个用户!");
        Thread.sleep(1500);
    }

    @Override
    public String[] selectUsers() throws Exception {
        System.out.println("查询出3个用户");
        String[] names = {"小凡","小七","小猫"};
        Thread.sleep(3000);
        return names;
    }
}

代理工具类

public class ProxyUtil {
    public static UserService createProxy(UserService userService) {
        UserService userProxy = (UserService) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                new Class[] { UserService.class }, (proxy, method, args) -> {
                    if (method.getName().equals("login") ||
                        method.getName().equals("deleteUsers") ||
                        method.getName().equals("selectUsers") ) {
                        long begin_date = System.currentTimeMillis();
                        Object rs = method.invoke(userService,args);
                        long end_date = System.currentTimeMillis();
                        System.out.println(method.getName() + "方法执行耗时:" + (end_date - begin_date) / 1000.0 + "s");
                        return rs;
                    } else {
                        Object rs = method.invoke(userService,args);
                        return rs;
                    }
                });
        return userProxy;
    }
}

实现类

public class Test {
    public static void main(String[] args) throws Exception {
//        UserService userService = new UserServiceImpl();
        UserService userService = ProxyUtil.createProxy(new UserServiceImpl());
        userService.login("admin","123456");
        System.out.println("------------------------------------");
        userService.deleteUsers();
        System.out.println("------------------------------------");
        String[] userNames = userService.selectUsers();
        System.out.println("查询到的用户名为:" + Arrays.toString(userNames));
        System.out.println("------------------------------------");
    }
}

什么是AOP?

AOP为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理
实现程序功能的统一维护的一种技术。

AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍
生范型。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序
的可重用性,同时提高了开发的效率。

常用术语:

Target(目标对象):代理的目标对象
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方
法类型的连接点
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知
Aspect(切面):是切入点和通知(引介)的结合合
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而Aspect采用编译期织入和类装载期织入

AOP 的作用及其优势

作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强

优势:减少重复代码,提高开发效率,并且便于维护

目标 + 增强(日志) = 切面

AOP 的动态代理技术

常用的动态代理技术
JDK 代理:基于接口的动态代理技术
cglib代理:基于父类的动态代理技术

tips: cglib的代理对象是目标对象的子类,而jdk代理对象和目标对象都实现了目标接口,jdk的代理对象还继承了Proxy
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值