Spring之注解实现aop(面向切面编程)

先说一个Spring是什么吧,大家都是它是一个框架,但框架这个词对新手有点抽象,以致于越解释越模糊,不过它确实是个框架的,但那是从功能的角度来定义的,从本质意义上来讲,Spring是一个库,一个Java库,所以我个人觉得应该这样回答Spring是什么:Spring是一个库,它的功能是提供了一个软件框架,这个框架目的是使软件之间的逻辑更加清晰,配置更灵活,实现这个目的的手段使用AOP和IoC,而AOP和IoC是一种思想,是一种什么样的思想呢,等下细说,先说AOP在Java里是利用反射机制实现(你也可以认为是动态代理,不过动态代理也是反射机制实现的,所以还是先不要管动态代理,我们这里化繁为简,不让它干扰咱们对AOP的理解),如何使用AOP呢,很简单滴,等下介绍。

下面先说AOP是什么样的思想,我们一步一步慢慢来,先看一下传统程序的流程,比如银行系统会有一个取款流程
这里写图片描述

我们可以把方框里的流程合为一个,另外系统还会有一个查询余额流程,我们先把这两个流程放到一起:

这里写图片描述

有没有发现,这个两者有一个相同的验证流程,我们先把它们圈起来再说下一步:

这里写图片描述

有没有想过可以把这个验证用户的代码是提取出来,不放到主流程里去呢,这就是AOP的作用了,有了AOP,你写代码时不要把这个验证用户步骤写进去,即完全不考虑验证用户,你写完之后,在另我一个地方,写好验证用户的代码,然后告诉Spring你要把这段代码加到哪几个地方,Spring就会帮你加过去,而不要你自己Copy过去,这里还是两个地方,如果你有多个控制流呢,这个写代码的方法可以大大减少你的时间,不过AOP的目的不是这样,这只是一个“副作用”,真正目的是,你写代码的时候,事先只需考虑主流程,而不用考虑那些不重要的流程,懂C的都知道,良好的风格要求在函数起始处验证参数,如果在C上可以用AOP,就可以先不管校验参数的问题,事后使用AOP就可以隔山打牛的给所有函数一次性加入校验代码,而你只需要写一次校验代码。不知道C的没关系,举一个通用的例子,经常在debug的时候要打log吧,你也可以写好主要代码之后,把打log的代码写到另一个单独的地方,然后命令AOP把你的代码加过去,注意AOP不会把代码加到源文件里,但是它会正确的影响最终的机器代码。

现在大概明白了AOP了吗,我们来理一下头绪,上面那个方框像不像个平面,你可以把它当块板子,这块板子插入一些控制流程,这块板子就可以当成是AOP中的一个切面。所以AOP的本质是在一系列纵向的控制流程中,把那些相同的子流程提取成一个横向的面,这句话应该好理解吧,我们把纵向流程画成一条直线,然把相同的部分以绿色突出,如下图左,而AOP相当于把相同的地方连一条横线,如下图右,这个图没画好,大家明白意思就行。
这里写图片描述这里写图片描述

这个验证用户这个子流程就成了一个条线,也可以理解成一个切面,aspect的意思我认为是方面,你用什么实物去类比,只要你能理解都可以。这里的切面只插了两三个流程,如果其它流程也需要这个子流程,也可以插到其它地方去。

步骤
1:Aop(aspect object programming)面向切面编程,名词解释:
1.1:功能:让关注点代码与业务逻辑代码分离
1.2:关注点
    重复代码就叫做关注点
1.3:切面
    关注点形成的类,就叫做切面(类)
    面向切面编程,就是指对很多功能都有的重复代码抽取,再在运行的时候往业务方法上动态植入"切面类代码";
1.4:切入点
    执行目标对象方法,动态植入切面代码
    可以通过切入点表达式,指定拦截那些类的那些方法,给指定的类在运行的时候植入切面类代码;
2:注解方式实现aop编程
2.1:开发步骤
    (1):先引入aop相关的jar文件
        spring-aop-3.2.5.RELEASE.jar【去spring3.2源码里面找】
        aopalliance.jar【去spring2.5源码/lib/aopalliance文件里面找】
        aspectjweaver.jar【去spring2.5源码/lib/aspectj文件里面找】或者【aspectj-1.8.2/lib/aspectjweaver.jar】
        aspectjrt.jar【去spring2.5源码/lib/aspectj文件里面找】或者【aspectj-1.8.2/lib/aspectjrt.jar】

    (2):bean.xml中引入aop名称空间:
             拷贝之后的bean.xml如下所示:

                    <?xml version="1.0" encoding="UTF-8"?>
                    <beans xmlns="http://www.springframework.org/schema/beans"
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xmlns:p="http://www.springframework.org/schema/p"
                        xmlns:context="http://www.springframework.org/schema/context"
                        xmlns:aop="http://www.springframework.org/schema/aop"
                        xsi:schemaLocation="
                            http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop.xsd">

                    </beans>

     (3):bean.xml中开启aop注解扫描,如下配置所示:

            <?xml version="1.0" encoding="UTF-8"?>
                <beans xmlns="http://www.springframework.org/schema/beans"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xmlns:p="http://www.springframework.org/schema/p"
                    xmlns:context="http://www.springframework.org/schema/context"
                    xmlns:aop="http://www.springframework.org/schema/aop"
                    xsi:schemaLocation="
                        http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context.xsd
                        http://www.springframework.org/schema/aop
                        http://www.springframework.org/schema/aop/spring-aop.xsd">

                      <!-- 开启注解扫描 -->
                      <context:component-scan base-package="com.bie.aop"></context:component-scan>   

                      <!-- 开启aop注解方式,默认为false -->    
                      <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

                </beans>        

        (4):开始写一个切面类,源码如下所示:    

                    package com.bie.aop;

                    import org.aspectj.lang.annotation.After;
                    import org.aspectj.lang.annotation.Aspect;
                    import org.aspectj.lang.annotation.Before;
                    import org.aspectj.lang.annotation.Pointcut;
                    import org.springframework.stereotype.Component;

                    @Component  //加入到IoC容器
                    @Aspect  //指定当前类为切面类
                    public class Aop {

                        //指定切入点表达式,拦截那些方法,即为那些类生成代理对象
                        //@Pointcut("execution(* com.bie.aop.UserDao.save(..))")  ..代表所有参数
                        //@Pointcut("execution(* com.bie.aop.UserDao.*())")  指定所有的方法
                        //@Pointcut("execution(* com.bie.aop.UserDao.save())") 指定save方法

                        @Pointcut("execution(* com.bie.aop.UserDao.*(..))")
                        public void pointCut(){

                        }

                        @Before("pointCut()")
                        public void begin(){
                            System.out.println("开启事务");
                        }

                        @After("pointCut()")
                        public void close(){
                            System.out.println("关闭事务");
                        }

                    }       

    (5):写好切面类就可以写执行目标对象方法,接口和实现类如下所示:
                        package com.bie.aop;

                            public interface IUserDao {

                                public void save();
                            }


                        package com.bie.aop;

                        import org.springframework.stereotype.Component;

                        @Component
                        public class UserDao implements IUserDao{

                            @Override
                            public void save() {
                                System.out.println("..核心业务--核心业务..");
                            }



        (6):最后就可以进行进行测试了,源码如下所示:

                    package com.bie.aop;
                    import org.junit.Test;
                    import org.springframework.context.ApplicationContext;
                    import org.springframework.context.support.ClassPathXmlApplicationContext;

                    public class AopTest {

                        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

                        //目标对象有实现接口,spring会自动选择"jdk代理【动态代理】"
                        //动态代理的标识:class com.sun.proxy.$Proxy10
                        @Test
                        public void test01(){
                            IUserDao dao =  (IUserDao) ac.getBean("userDao");
                            System.out.println(dao.getClass());
                            dao.save();
                        }


                        //class com.bie.aop.OrderDao$$EnhancerByCGLIB$$4952a60a
                        //目标对象没有实现接口,spring会用"cglib代理哦"
                        @Test
                        public void testCglib(){
                            OrderDao dao =  (OrderDao) ac.getBean("orderDao");
                            System.out.println(dao.getClass());
                            dao.save();
                        }
                    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值