zoukankan      html  css  js  c++  java
  • 重新学习Spring2——IOC和AOP原理彻底搞懂

    一、AOP


    1 Spring AOP 的实现原理

    • 是对OOP编程方式的一种补充。翻译过来为“面向切面编程”。

    • 1 AspectJ是静态代理的增强:所谓静态代理就是AOP框架会在便一阶段生成AOP代理类,也叫编译器增强。

    • 2 使用Spring AOP

      • 与AspectJ 的静态代理不同,Spring AOP使用的是动态代理,动态代理指AOP框架不会去修改字节码,而是在内存中临时生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并在特定的切点做了增强处理,并回调原对象的方法。
      • Spring AOP中的动态代理有两种:JDK动态代理(代理必须实现一个接口)、CGLIB动态代理(代理可以不实现接口)
      • 几个概念:
        • 切面(Advisor):是AOP中的一个术语,表示从业务逻辑中分离出来的横切逻辑比如性能监控、日志处理、权限控制等
          这些功能都可以从核心的业务逻辑中抽离出去。可以解决代码耦合的问题,职责更加单一。封装了增强和切点。
        • 增强(Advice):增强代码的功能的类,横切到代码中。
        • 目标:目标方法(JDK代理)或目标类(CGLIB代理)。
        • 代理:通过ProxyFactory类生成,分为JDK代理、CGLIB代理。
        • 切点:通过一个条件来匹配拦截的类,这个条件成为切点。
        • 连接点:作为增强方法的入参,可以获取目标方法的信息。
      • 增强
        • 织入(Weaving):将切面应用到目标对象并导致代理对象创建的过程。
          • 1 前置增强(Before):在目标方法前调用。
          • 2 后置增强(AfterAdvice):在目标方法后调用。
          • 3 环绕增强(AroundAdvice):将Before和After,甚至抛出增强和返回增强合到一起。
          • 4 返回增强(AfterReturningAdvice):在方法返回结果后执行,该增强可以接收到目标方法返回的结果。
          • 5 抛出增强(AfterThrowingAdvice):在目标方法抛出对应的类型后执行,可以接收到对应的异常信息。
        • 引入增强(DeclareParentsAdvice):想让程序在运行的时候动态实现某个接口,需要引入增强。
    • 3 注解:Spring + AspectJ

      • 1 对切面类添加 @Aspect 注解将切面类和目标类放入到IOC容器中,可以通过<context:component-scan base-package=""/>进行扫描。
      • 2 添加增强方法(包括增强类型和切点表达式,以及连接点)。
      • 3 在Spring 配置文件中添加<aop:aspectj-autoproxy proxy-target-class="true"/> ,false表示只能代理接口(JDK动态代理),true表示代理类(CGLIB代理)。
      • 3.1 通过切点表达式(AspectJ execution)进行拦截

        • 步骤一:配置pox.xml:
    <!--Spring AOP依赖-->
    <dependency>
    	<groupId>org.springframework</groupId>
    	<artifactId>spring-aop</artifactId>
    	<version>${spring.version}</version>
    </dependency>
    <dependency>
          <groupId>org.springframework</groupId>
         <artifactId>spring-aspects</artifactId>
         <version>${spring.version}</version>
    </dependency>
    
    • 步骤二:spring-config.xml
    <!-- 注解扫描-->
    <context:component-scan base-package="com.sean.aoptest"></context:component-scan>
    <!-- 设置aop动态代理类型:true为代理类,false为代理接口 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    
    • 步骤三:编写代码,在这里我上传一段测试代码
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"classpath:spring-config-test.xml"})
    public class SpringTest{
    	
    	@Autowired
    	private Student student;
    	@Test
    	public void test01(){
    		System.out.println(student.say("zengxing"));
    	}
    }
    
    @Component
    class Student implements Person{
    
    	@Override
    	public String say(String name) {
    		// TODO Auto-generated method stub
    //		if (name.equals("zengxing")) {
    //			throw new RuntimeException("名字不能是" + name);		//要抛出运行时异常
    //		}
    		return "Hello, " + name;
    	}
    	
    }///*
    around before...
    before
    around after...
    after
    str:Hello, zengxing
    afterReturningAdvice
    Hello, zengxing
    *///
    
    @Aspect
    @Component
    class LoggingAspect{
    	//前置
    	@Before("execution(String say(String))")
    	public void before(JoinPoint point){
    		System.out.println("before");
    	}
    	
    	//后置
    	@After("execution(String say(String))")
    	public void after(JoinPoint point){
    		System.out.println("after");
    	}
    	
    	//环绕
    	@Around("execution(String say(String))")
    	public Object around(ProceedingJoinPoint point) throws Throwable{
    		System.out.println("around before...");
    		Object result = point.proceed();
    		System.out.println("around after...");
    		return result;
    	}
    	
    	//返回
    	@AfterReturning(value="execution(String say(String))", returning="str")
    	public void afterReturningAdvice(JoinPoint point, String str){
    		System.out.println("str:" + str);
    		System.out.println("afterReturningAdvice");
    	}
    	
    	//抛出
    	@AfterThrowing(value = "execution(String say(String))", throwing = "e")
    	public void afterThrowingAdvice(JoinPoint point, Exception e){
    		String message = e.getMessage();
    		System.out.println(message);
    		System.out.println("AfterThrowingAdvice...");
    	}
    }
    
    • 3.2 通过切点注解表达式(AspectJ @annotation)进行拦截

      • 开发步骤:
        • 1 定义注解类
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface AuthorityTag { }
    
    • 2 为切面类中增强指定注解表达式
    @Aspect
    @Component
    class AuthorityAspect{
    	@Before("@annotation(com.sean.aoptest.AuthorityTag)")
    	public void before(JoinPoint point){
    		System.out.println("authority before");
    	}
    }
    
    • 3 在目标类目标方法上标注注解
    @Component		//将对象放入到IOC容器中
    class Car1 implements Wheel{
    	
    	@AuthorityTag	//标注切入的的增强
    	@Override
    	public void run(){
    		System.out.println("I am a car, i can run");
    	}
    }
    
    • 4 小的知识点

      • 利用方法签名编写 AspectJ 切点表达式
        • execution * com.sean.Calculator.* (…):匹配Calculator中声明的所有方法,
          第一个 * 代表任意修饰符及任意返回值。第二个 * 代表任意方法。…匹配任意数量的参数。若目标类与接口与该切面在同一个包中,可以省略包名。
        • execution public * Calculator.*(…):匹配ArithmeticCalculator 接口的所有公有方法。
        • execution public double Calculator.*(…):匹配Calculator中返回double类型数值的方法。
        • execution public double Calculator.*(double, …):匹配第一个参数为double类型的方法,…匹配任意数量任意类型的参数。
        • execution public double Calculator.*(double, double):匹配参数类型为double,double类型的方法。
      • 可以结合切点表达式使用 &&, ||, ! 来合并。如:
        • execution(void run()) || execution(void say())
      • 切面优先级:
        • 可以通过实现Ordered接口或利用@Order注解指定。
        • 1 实现Ordered接口,getOrder()方法返回的值越小,优先级越高。
        • 2 使用@Order注解,需要出现在注解中,同样是值越小优先级越高。

    参考博客:https://blog.csdn.net/qq_16605855/article/details/73465865

  • 相关阅读:
    python中map()函数
    Numpy学习—np.random.randn()、np.random.rand()和np.random.randint()
    列表、集合和字典推导式
    pandas iloc函数
    python -- 类中self到底有什么用?再续
    python apply()函数
    python 中关于self到底有什么用续
    python——类中的self到底有什么作用
    类初始化的参数可以是任何形式
    python高级(元类、自定义元类)
  • 原文地址:https://www.cnblogs.com/sean-zeng/p/11024768.html
Copyright © 2011-2022 走看看