Java教程

【复习 spring IOC与AOP思想】

本文主要是介绍【复习 spring IOC与AOP思想】,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

控制反转(Inversion of Control:IoC)

  IOC 把对象的创建交给框架,它包括依赖注入(DI)和依赖查找,它的作用是降低程序间的耦合(依赖关系)。

而所谓依赖注入(DI),就是把底层类作为参数传入上层类,实现上层类对下层类的“控制”,我们需要进行控制反转(IoC),及上层控制下层,而不是下层控制着上层,这样可以减少维护代码的困难度。

  简单来说,IOC特性 就是 把new对象的权利交给了Spring容器来处理,当前就是简述其设计实现思想,实际开发大多通过注解注入即可,就拿注解注入来举例:

  主要有四种注解可以注册bean,每种注解可以任意使用,只是语义上有所差异:

      @Component:可以用于注册所有bean
      @Repository:主要用于注册dao层的bean
      @Controller:主要用于注册控制层的bean
      @Service:主要用于注册服务层的bean

  还有两个注解是用于描述依赖关系:

  @Resource:java的注解,默认以byName的方式去匹配与属性名相同的bean的id,如果没有找到就会以byType的方式查找。

        如果byType查找到多个的话,使用@Qualifier注解(spring注解)指定某个具体名称的bean。

  @Autowired:spring注解,默认是以byType的方式去匹配类型相同的bean,如果只匹配到一个,那么就直接注入该bean,无论要注入的 bean 的 name 是什么;如果匹配到多个,就会根据byName去找对应bean名称的。

 

切面编程(AOP)

  AOP的基本概念如下:

  (1)Aspect(切面):通常是一个类,里面可以定义切入点(Pointcut )和通知(Advice)

  (2)JointPoint(连接点):表示在程序中明确定义的点,一般是方法的调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point

  (3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around,Advice 定义了在 切入点 (PointCut) 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。

  (4)Pointcut(切入点):就是一组带有通知(advice)的连接点(JointPoint),在程序中主要体现为书写切入点表达式,并定义相应的通知(advice) 将要发生的地方。

  (5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

  (6)Weaving(织入):将 切面(Aspect)和其他对象连接起来, 并创建 Adviced object 的过程

 

  这些概念比较抽象,可以通过一个demo来理解:

  首先,测试方法为jdk代理(Spring中的AOP代理:代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。)

  jdk的Proxy:动态代理,执行的时候处理,要求必须有接口、实现类,代理创建的是实现类的子类。  

  然后xml实现和注解实现两种方式 我们选择注解实现:

  代码如下:

  接口类:

package com.wang.service;

/**
 * on 2022/2/6 19:43
 */
public interface HelloWorldService {
    public void sayHello(int id);
}

  接口实现类:

package com.wang.service.Impl;

import com.wang.pojo.User;
import com.wang.service.HelloWorldService;
import org.springframework.stereotype.Component;

/**
 *  2022/2/6 19:44
 */

@Component("HelloWorldServiceImpl")
public class HelloWorldServiceImpl implements HelloWorldService {

    @Override
    public void sayHello(int id) {
        System.out.println("Spring AOP——这里是bean内方法");
    }
}

  切面类:

package com.wang.Aspect;

import com.wang.pojo.User;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 *  on 2022/2/6 19:49
 */

@Component    //声明这是一个组件
@Aspect       ///声明这是一个切面Bean
public class HelloWorldAspect {
    //定义切点
    @Pointcut("execution(* com.wang..*.*(..)) ")
    public void sayings(){
    }

    /**
     * 前置通知(注解中的sayings()方法,其实就是上面定义pointcut切点注解所修饰的方法名,那只是个代理对象,不需要写具体方法,
     * 相当于xml声明切面的id名,如下,相当于id="embark",用于供其他通知类型引用)
     * <aop:config>
     <aop:aspect ref="mistrel">
     <!-- 定义切点 -->
     <aop:pointcut expression="execution(* *.saying(..))" id="embark"/>
     <!-- 声明前置通知 (在切点方法被执行前调用) -->
     <aop:before method="beforSay" pointcut-ref="embark"/>
     <!-- 声明后置通知 (在切点方法被执行后调用) -->
     <aop:after method="afterSay" pointcut-ref="embark"/>
     </aop:aspect>
     </aop:config>
     */
/*
    @Before("sayings()")
    public void sayHello(){
        System.out.println("注解类型前置通知");
    }

    //后置通知
    @After("sayings()")
    public void sayGoodbey(){
        System.out.println("注解类型后置通知");
    }
*/
    @Before(value="bean(HelloWorldServiceImpl) && args(id,..)", argNames="id")
    public void beforeWithParam(int id) {
        System.out.println("带参数的前置通知,也可以理解为我们定义一个Advice来拦截这个带参数id的这个方法,bean类为HelloWorldServiceImpl");
        System.out.println(this.getClass().getName()+" ID is : " + id);
    }

    //环绕通知。注意要有ProceedingJoinPoint参数传入。
    @Around(value = "sayings()")
    public void sayAround(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("注解类型环绕通知..环绕前");
        pjp.proceed();//执行方法,即执行被通知函数
        System.out.println("注解类型环绕通知..环绕后");
    }

}

  启动类:

package com.wang.AopTest;

import com.wang.service.HelloWorldService;
import com.wang.service.Impl.HelloWorldServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
 *  on 2022/2/6 19:51
 */
public class HelloWorldTest {
    public static void main(String[] args) {

        //这个是application容器,所以就会去所有的已经加载的xml文件里面去找,包括jar包里面的xml文件
        ApplicationContext context = new FileSystemXmlApplicationContext("D:\\IDEAprojects\\Mybatis-study\\mybatis-04\\src\\main\\resources\\applicationContext.xml");

        //通过ApplicationContext.getBean(beanName)动态加载数据(类)【获取Spring容器中已初始化的bean】。
        HelloWorldServiceImpl helloWorld=(HelloWorldServiceImpl) context.getBean("HelloWorldServiceImpl");

        int id = 4;
        //执行动态加载到的类的方法
        helloWorld.sayHello(id);

    }
}

配置文件:applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.3.xsd">



    <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.wang"/>
    <!-- 开启aop注解方式,此步骤s不能少,这样java类中的aop注解才会生效 -->
    <aop:aspectj-autoproxy/>
    <!-- 强制使用cglib代理,如果不设置,将默认使用jdk的代理,但是jdk的代理是基于接口的 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

</beans>

  注意:切面类要添加注解@Aspect,不然不会触发aop的那几个注解,比如@Before 等。

 

 

参考连接:https://blog.csdn.net/q982151756/article/details/80513340 (例子很形象)

     https://www.cnblogs.com/liuruowang/p/5711563.html

这篇关于【复习 spring IOC与AOP思想】的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!