• Spring AOP理解


        Spring的核心思想的IOC和AOP。最近学习AOP,对切面的学习有了进一步的认识。

        Spring用代理类包裹切面,把他们织入到Spring管理的bean中。也就是说代理类伪装成目标类,它会截取对目标类中方法的调用,让调用者对目标类的调用都先变成调用伪装类,伪装类中就先执行了切面,再把调用转发给真正的目标bean。这样可以实现对业务代码的最小化侵入。使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性。Spring中日志记录,性能统计,安全控制,事务处理等都是通过AOP来管理的。

    伪装类的实现有两种方式:1.实现和目标类相同的接口。这种兄弟模式下,spring会使用JDK的java.lang.reflect.Proxy类,它允许Spring动态生成一个新类来实现必要的接口,织入通知,并且把对这些接口的任何调用都转发到目标类。

                                       2.生成子类调用,用子类来做为伪装类。这种父子模式下,spring使用CGLIB库生成目标类的一个子类,在创建这个子类的时候,spring织入通知,并且把对这个子类的调用委托到目标类。

    相比之下,还是兄弟模式好些,能更好的实现松耦合,尤其在今天都高喊着面向接口编程的情况下,父子模式只是在没有实现接口的时候,也能织入通知,应当做一种例外。

     下面看一个AOP的小应用。目的是为了在addStudent方法执行前后通过AOP来进行相关操作。

    在上下文中配置aspectJ。

    <aop:aspectj-autoproxy/>
    //定义切面,切点。也可以通过注解来实现切面的和切点标识。
    <aop:config>
            <aop:aspect id="StudentServiceAspect" ref="studentServiceAspect">
                <aop:pointcut id="businessService" expression="execution(* com.lufax.test.commen.studentService.*.*(..))"/>
                <aop:before method="doBefore" pointcut-ref="businessService"/>
                <aop:after method="doAfter" pointcut-ref="businessService"/>
                <aop:around method="doAround" pointcut-ref="businessService"/>
            </aop:aspect>
        </aop:config>

    下面定义studentService的接口。

    public interface StudentService {
        public void addStudent(String name);
    }

    studentService的实现类如下。

    public class StudentServiceImp implements StudentService {
    
        public void addStudent(String name){
            System.out.println("----正在添加" + name+"----");
        }
    }

    以上接口和实现都是正常的业务逻辑。下面写切面。

    public class StudentServiceAspect {
        //在业务代码执行前运行
        public void doBefore(){
            System.out.println("类名:");
            System.out.println("doBefore:开始添加学生");
        }
    //业务代码执行后运行
    public void doAfter(JoinPoint jp){ System.out.println("doAfter:添加完毕");
    //可以通过Joinpoint类来实现日志的打印。记录切点下类和方法名、参数,以便后续快速定位问题所在。 System.out.println(
    "[类名+"+jp.getTarget().getClass().getName()+"],"+ "[方法名:"+jp.getSignature().getName()+"],"+ "[参数:"+jp.getArgs()[0]+"]"); }
    //环绕通知,retVal是返回值。这里为null
    public Object doAround(ProceedingJoinPoint pjp)throws Throwable{ System.out.println("doAround:加入前"); Object retVal= pjp.proceed(); System.out.println(retVal); System.out.println("doAround:加入后"); return retVal; } }

    通过注解实现。

    @Aspect
    public class StudentServiceAspect {
    
        @Before(value="execution(* com.lufax.test.commen.studentService.*.addStudent(..)) ")
        public void doBefore(){
            System.out.println("类名:");
            System.out.println("doBefore:开始添加学生");
        }
    
        @After(value="execution(* com.lufax.test.commen.studentService.*.addStudent(..))")
        public void doAfter(JoinPoint jp){
            System.out.println("doAfter:添加完毕");
            System.out.println("[类名+"+jp.getTarget().getClass().getName()+"],"+
                               "[方法名:"+jp.getSignature().getName()+"],"+
                               "[参数:"+jp.getArgs()[0]+"]");
        }
    
        @Around(value="execution(* com.lufax.test.commen.studentService.*.addStudent(..))")
        public Object doAround(ProceedingJoinPoint pjp)throws Throwable{
            System.out.println("doAround:加入前");
            Object retVal= pjp.proceed();
            System.out.println(retVal);
            System.out.println("doAround:加入后");
            return retVal;
        }
    }

    最后写测试类。

    @Test
        public void test_AopAspectJ() {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml","dataSource.xml");
            StudentService studentService = (StudentService) applicationContext.getBean("studentService");
            studentService.addStudent("张三");
        }

    运行结果如下:

    类名:
    doBefore:开始添加学生
    doAround:加入前
    ----正在添加张三----
    doAfter:添加完毕
    [类名+com.lufax.test.commen.studentService.StudentServiceImp],[方法名:addStudent],[参数:张三]
    null
    doAround:加入后
  • 相关阅读:
    react给input元素中文输入的时候自动转成字符串bug
    charles代理
    es6和es5函数参数和arguments的差别
    Uncaught InvalidStateError: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.
    Node 开发概述
    对Flutter路由管理库Fluro的封装
    Flutter 切换标签显示对应的列表+Provide状态管理实例
    Flutter 商城实例 分类列表
    Flutter 入口页面及底部导航栏实例制作
    Flutter 建立项目和编写入口文件
  • 原文地址:https://www.cnblogs.com/K2154952/p/5940463.html
Copyright © 2020-2023  润新知