栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

aop实现原理(springioc和aop原理)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

aop实现原理(springioc和aop原理)

IOC 概念

inversion of control【控制反转】,将对象的创建权反转给spring
注意:IOC只是用来降低程序的耦合性,让代码更为合理,不能实现具体的业务功能。

好处:
• 解耦,降低程序将的耦合性

底层原理:
• 工厂+配置文件+反射

通过工厂加反射加配置文件的方式实现程序的解耦

我们现在编写的代码都是遵循的 JavaEE 三层架构,分为 web 层,service 层,dao层。但是之前写的代码存在一些潜在的问题:

以 Servlet 中的代码为例,之前的代码在得到某个 Service 的实现类的时候都是直接 new 实现类。一旦实现类产生了改变,new 实现类的代码就要跟着修改。如在 UserServlet 中需要使用 UserService 的实现:

//声明UserService业务对象
private UserService service = new UserServiceImpl();

如果现在实现方案产生了改变,我们在业务层写了一个新的实现类UserServiceImpl2

public class UserServiceImpl2 implements UserService {
    xxx(){
    }
    ...
}

虽然现在是 service 层的实现产生了变化,但是 web 层的代码需要作出修改,我们需要将 UserServlet 的代码改为:

//声明UserService业务对象
private UserService service = new UserServiceImpl2();

其中某一层的实现产生改变,相关的其它层的代码也必须要跟着产生变化,这就叫代码的耦合

要解决这个问题,需要两个步骤:
【步骤1】引入一个名为 applicationContext.xml 的配置文件,格式如下(maven 工程放入 resources 目录):



    
    ...
    

在这个配置文件中定义了很多的 bean 标签,每个 bean 标签都有一个唯一的 id 属性和一个对应的 class 属性,class 属性的值就是某个 service 或者 其它 实现类的全限定名。

【步骤2】创建一个 BeanFactory 工厂类,在这个类中提供一个名为 getBean 的工具方法,在方法中根据用户传入的 id,解析 applicationContext.xml 文件,得到 id 对应的 class 值,反射生成实例并返回。

public class BeanFactory {
    public static Object getBean(String id){
        try {
            // 获取xml文件的真实路径
            String path = BeanFactory.class.getClassLoader().getResource("applicationContext.xml").getPath();
            File file = new File(path);
            // 解析xml文件得到文档对象
            document document = Jsoup.parse(file, "UTF-8");
            // 从文档中根据id值获取bean标签对应的元素
            Element beanEle = document.getElementById(id);
            // 根据class属性名获取属性值
            String className = beanEle.attr("class");
            // 将class属性值对应的类加载进内存
            Class clazz = Class.forName(className);
            // 创建实例对象
            Object obj = clazz.newInstance(); 
            
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

注意:代码中使用了 jsoup 的 api,所以要在工程的 pom.xml 文件中引入 jsoup 对应的依赖。


    org.jsoup
    jsoup
    1.10.3

• 经过以上修改,当我们需要使用某一个功能的实现类的时候,不再是直接 new 实现类,而是通过 BeanFactory 中的 getBean 方法获取,如:

 userService = (UserService) BeanFactory.getBean("userService");

• 而且,当我们需要切换某一个功能的实现类的时候,只需要修改配置文件中该实现类对应的 class 属性的值,其它代码不需要经过任何修改。例如,现在userService的实现方案产生了改变,有一个新的 UserServiceImpl2出现,我们只需要修改配置文件中 userService对应的 class 值即可


这样就达到了在切换底层实现时没有修改 java 源代码的需求,也就是解除了层与层之间的耦合。这个通过 工厂+配置文件+反射 实现解耦的方案,就是 Spring 中的 IOC(控制反转) 思想。

AOP 概念

Aspect Oriented Programming【面写切面编程】
是一种在运行期间通过动态代理,实现在不修改源代码的情况下给程序统一添加功能的编程思想

需求:需要统计 service 中所有 findXXX 相关的查询方法所消耗的时长

分析:
• 不可能在所有 service 中的所有查询方法中加入统计时长的代码,最好这个代码只写一次
• 之前 dao 中的查询方法没有统计时长的功能,现在我希望它有这个功能,其实就是要增强方法的功能,可以想到动态代理。
• 动态代理是对某个实现了接口的对象进行增强,我们的 dao 都实现了接口,这些 dao 的对象再哪创建的?在 BeanFactory 中反射生成的。所以这个代码应该写在 BeanFactory 中。代码如下:

public class BeanFactory {
    public static Object getBean(String id){
        try {
            // 获取xml文件的真实路径
            String path = BeanFactory.class.getClassLoader().getResource("applicationContext.xml").getPath();
            File file = new File(path);
            // 解析xml文件得到文档对象
            document document = Jsoup.parse(file, "UTF-8");
            // 从文档中根据id值获取bean标签对应的元素
            Element beanEle = document.getElementById(id);
            // 根据class属性名获取属性值
            String className = beanEle.attr("class");
            // 将class属性值对应的类加载进内存
            Class clazz = Class.forName(className);
            // 创建实例对象
            Object obj = clazz.newInstance();  // 被代理对象
            // 判断当前获取的是不是service实现类
            if(id.endsWith("Service")){
                Object objProxy = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {
                    // 调用代理对象的任何方法,会执行invoke方法
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 获取方法名
                        String methodName = method.getName();
                        // 判断是不是查询方法
                        if (methodName.startsWith("find")){
                            // 获取开始时间
                            long startTime = System.currentTimeMillis();
                            // 执行查询方法
                            Object rtValue = method.invoke(obj,args);
                            // 获取结束时间
                            long endTime = System.currentTimeMillis();
                            // 获取类名
                            String simpleName = obj.getClass().getSimpleName();
                            System.out.println(simpleName+"类的"+methodName+"方法执行消耗了"+(endTime-startTime)+"时长");
                            // 返回结果
                            return rtValue;
                        }else {
                            // 其它方法,原封不动的调用
                            return method.invoke(obj, args);
                        }
                    }
                });
                // 返回增强之后的代理对象
                return objProxy;
            }
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

这部分代码,就是 Spring 中的另一个核心思想 AOP(面向切面编程)

概念:AOP,面向切面编程

作用:在不修改源代码的情况下统一增强程序的功能

原理:动态代理

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/773371.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号