Spring框架之IOC和AOP

Spring框架之AOP

  • 一、 spring IOC的使用
    • 1.1 IOC的概念
    • 1.2 依赖注入和控制反转的形式
  • 二、为什么使用AOP
  • 三、什么是AOP
  • 四、怎么使用AOP
    • 1、导入相关的jar包
    • 2、定义切面类
    • 3、在Spring配置文件中添加aop命名空间以及schema文件
    • 4、定义切面类:把切面类放到Spring容器
    • 5、配置切面:配置切入的规则
  • 五、AOP的实例
    • 1、返回后增强、环绕增强、抛出异常后增强处理虽然可以对目标方法的异常进行处理
    • 2、注解种类
  • 六、AOP动态处理
  • 七、AOP测试

现实例子:
https://www.jianshu.com/p/6565361f6845?tdsourcetag=s_pctim_aiomsg

一、 spring IOC的使用

1.1 IOC的概念

    IOC是控制反转:
        java的bean或者pojo类一般是自主使用new进行创建,现在通过使用spring框架,将java类的创建权限
        反转给spring容器,这就是控制反转;
        从被管理的类的角度的说的;
    DI依赖注入:
        spring容器根据被托管的类或者变量之间的依赖关系,而注入这个类的实例对象或者变量的值;
        从spring容器的角度说的;

1.2 依赖注入和控制反转的形式

    1、属性依赖注入
        需要提供属性的setter方法接口;
    2、构造方法依赖注入
        需要提供对应参数个数的重载的构造方法            
    3、工厂类依赖注入
        需要提供对应的工厂类;      
    
    注意:spring进行依赖注入时的依赖关系一般指的的是 类与类之间的 组合关系;

二、为什么使用AOP

想添加日志或者其他公共操作,如果采取创建工具类,把公共操作放在工具类的方法中,违背了开放-封闭以及单一职责的设计原则
Java设计原则:
https://blog.csdn.net/albenxie/article/details/72371102

三、什么是AOP

AOP采用自动化的方式,并不需要修改源代码,完成公共的操作,实现基于动态代理机制,遵循了开闭原则和单一职责原则
Java中三种代理模式:
https://www.cnblogs.com/jie-y/p/10732347.html
Spring框架之IOC和AOP_第1张图片
参考文档:Spring–AOP详解
https://www.open-open.com/lib/view/open1338175216901.html
https://blog.csdn.net/q982151756/article/details/80513340
AOP里面几个重要名词概述的概念:

术语 含义
Aspect(切面) 切入点+通知
joinPoint(连接点) 目标对象,所有可以增强的方法
Advice(通知/增强) 增强代码
PointCut(切入点) 目标对象,将要和已经增强的方法
Introduction(引入) 声明某个方法或字段
Target(目标对象) 被代理的对象
AOP 代理(AOp Proxy) AOP框架创建的对象用来实现切面
Weaving(织入) 将通知应用到切入点的过程

参考原文地址:https://blog.csdn.net/qq_39507327/article/details/81507224
概念的关系图:
Spring框架之IOC和AOP_第2张图片

四、怎么使用AOP

1、导入相关的jar包

<!--aop依赖包-->
<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.0.7.RELEASE</version>
</dependency>

2、定义切面类

//定义切面类
public class Logging {
    //在被代理对象方法的前面加公共操作
    public void before(){
        System.out.println("执行了before");
    }
    //在被代理对象方法的后面加公共操作
    public void after(){
        System.out.println("执行了after");
    }
}

3、在Spring配置文件中添加aop命名空间以及schema文件

xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"

4、定义切面类:把切面类放到Spring容器

<!--开启注解的支持-->
<context:annotation-config></context:annotation-config>
<!--指定扫描包的路径-->
<context:component-scan base-package="com.test"></context:component-scan>

<!--定义切面类:把切面类放到Spring容器-->
<bean id="logging" class="com.test.aspect.Logging"></bean>

5、配置切面:配置切入的规则

<!--配置切面:配置切入的规则-->
<aop:config>
      <!--配置切面-->
      <aop:aspect id="myAspect" ref="logging"><!--ref:注入的是bean的实例-->
            <!--配置切入点:切入的位置-->
            <aop:pointcut id="poointcut" expression="execution(* com.test.service.*.*(..))"></aop:pointcut>
                                                        <!--任意返回值类型  任意类  任意方法  多种参数-->
            <!--切入的时机:方法执行前还是执行后加等,指定把切面类中哪个公共操作进行通知-->
            <aop:before method="before" pointcut-ref="poointcut"></aop:before><!--前置增强-->
            <!--pointcut-re引用上面的切入点-->
            <aop:after method="after" pointcut-ref="poointcut"></aop:after><!--后置增强-->
      </aop:aspect>
</aop:config>

五、AOP的实例

1、返回后增强、环绕增强、抛出异常后增强处理虽然可以对目标方法的异常进行处理

1) Spring配置文件中

    <!--开启注解的支持-->
    <context:annotation-config></context:annotation-config>
    <!--指定扫描包的路径-->
    <context:component-scan base-package="com.test"></context:component-scan>

    <!--定义切面类:把切面类放到Spring容器-->
    <bean id="logging" class="com.test.aspect.Logging"></bean>
    <!--配置切面:配置切入的规则-->
    <aop:config>
        <!--配置切面-->
        <aop:aspect id="myAspect" ref="logging"><!--ref:注入的是bean的实例-->
            <!--配置切入点:切入的位置--><!--aop:pointcut配置切入点,expression配置表达式-->
            <aop:pointcut id="poointcut" expression="execution(* com.test.service.*.*(..))"></aop:pointcut>
                                                        <!--任意返回值类型  任意类  任意方法  多种参数-->
            <aop:after-returning method="after" pointcut-ref="poointcut"></aop:after-returning><!--返回后增强-->
            <aop:around method="around" pointcut-ref="poointcut"></aop:around><!--环绕增强-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="poointcut"></aop:after-throwing>
            <!--AOP的AfterThrowing处理虽然可以对目标方法的异常进行处理,但这种处理与直接使用catch捕捉不同,catch捕捉意味着完全处理该异常,
            如果catch块中没有重新抛出新的异常,则该方法可能正常结束;而AfterThrowing处理虽然处理了该异常,但它不能完全处理异常,
            该异常依然会传播到上一级调用者,即JVM。-->
        </aop:aspect>
    </aop:config>

2) 切面类中增加方法

//定义切面类
public class Logging {
    //在被代理对象方法的前面加公共操作
    public void before(){
        System.out.println("执行了before");
    }
    //在被代理对象方法的后面加公共操作
    public void after(){
        System.out.println("执行了after");
    }
    //在被代理对象方法的前后加公共操作
    public void around(ProceedingJoinPoint joinPoint)throws Throwable{
        System.out.println("方法执行前的操作:--------------");
        //执行主要方法
        Object result=joinPoint.proceed();
        System.out.println("方法执行后的操作:--------------");
        System.out.println("执行了"+joinPoint.getTarget()+"方法,方法的返回值是:"+result+"\t方法的名称:"+joinPoint.getSignature().getName());
    }
    public void afterThrowing(){
        System.out.println("执行了afterThrowing\n发生了系统异常");
    }
}

2、注解种类

参考资料:https://blog.csdn.net/m0_37626813/article/details/78558010
1、@controller 控制器(注入服务)

用于标注控制层,相当于struts中的action层

2、@service 服务(注入dao)

用于标注服务层,主要用来进行业务的逻辑处理

3、@repository(实现dao访问)

用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件.

4、@component (把普通pojo实例化到spring容器中,相当于配置文件中的

泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller、@Services等的时候),我们就可以使用@Component来标注这个类。

案例:

<context:component-scan base-package=”com.*”> 

上面的这个例子是引入Component组件的例子,其中base-package表示为需要扫描的所有子包。
共同点:被@controller 、@service、@repository 、@component 注解的类,都会把这些类纳入进spring容器中进行管理

六、AOP动态处理

参考资料:
https://www.jianshu.com/p/f6fd176ff42c?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

1) Spring配置文件中:

    <!--开启注解的支持-->
    <context:annotation-config></context:annotation-config>
    <!--指定扫描包的路径-->
    <context:component-scan base-package="com.test"></context:component-scan>

    <!--配置AOP动态处理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

2) 切面类中添加注解

//定义切面类
/*@Component把普通pojo实例化到spring容器中,相当于配置文件中的 */
//切面类加入IOC容器
@Component
@Aspect
/*aop:aspect配置切面,ref引入IOC容器中的切面类*/
public class Logging {
    //在被代理对象方法的前面加公共操作
    /*aop:before前置增强*/
    @Before("execution(* com.test.service.*.*(..))")
    public void before(){
        System.out.println("执行了before");
    }
    //在被代理对象方法的后面加公共操作
    @After("execution(* com.test.service.*.*(..))")
    public void after(){
        System.out.println("执行了after");
    }
    //在被代理对象方法的前后加公共操作
    @Around("execution(* com.test.service.*.*(..))")
    public void around(ProceedingJoinPoint joinPoint)throws Throwable{
        System.out.println("方法执行前的操作:--------------");
        //执行主要方法
        Object result=joinPoint.proceed();
        System.out.println("方法执行后的操作:--------------");
        System.out.println("执行了"+joinPoint.getTarget()+"方法,方法的返回值是:"+result+"\t方法的名称:"+joinPoint.getSignature().getName());
    }
    @AfterThrowing("execution(* com.test.service.*.*(..))")
    public void afterThrowing(){
        System.out.println("执行了afterThrowing\n发生了系统异常");
    }
}

七、AOP测试

    //UserService对象
    @Test
    public void testUserService(){
        //读取String配置文件
        ApplicationContext context=new ClassPathXmlApplicationContext("application-context.xml");
        //获取UserService对象
        UserService userService=(UserService)context.getBean("userService");
        //调用UserService对象的getCount方法
        userService.getCount();
    }

测试结果

方法执行前的操作:--------------
执行了before
执行了UserService的getCount方法!!
执行了UserDao的getCount方法!!
方法执行后的操作:--------------
执行了com.test.service.UserServiceImpl@5c7bfdc1方法,方法的返回值是:1	方法的名称:getCount
执行了after

Process finished with exit code 0

你可能感兴趣的:(spring,aop,java)