Spring学习笔记(三)

简介: Spring学习笔记

AOP概述及出现背景

面向切面编程

aop概述

AOP全称为Aspect Oriented Programming的缩写,意为:面向切面编程。将程序中公用代码进行抽离,通过动态代理实现程序功能的统一维护的一种技术。

使代码耦合性降低,提高了开发的效率。

aop可以完成的功能

日志记录,性能统计,安全控制,事务处理,异常处理等等。

aop与oop区别

OOP:(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。java实体类就是面向对象编程的最准确的体现。

AOP:则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。

spring AOP底层实现介绍

spring的AOP底层是由 JDK提供的动态代理技术 和 CGLIB(动态字节码增强技术)实现。

**JDK动态代理:**Jdk动态代理只针对于接口操作。

CGLIB:可以针对没有接口的java类和有接口的java类。

静态代理

package cn.cqie.service;
public interface UserService {
    void save();
}

目标Target

package cn.cqie.service;
public class UserServiceImpl implements UserService{
    @Override
    public void save() {
        System.out.println("UserServiceImpl.save");
    }
}

代理Proxy:代理类需要和目标类实现同一个接口。

package cn.cqie.service;
public class UserServiceProxyImpl implements UserService{
    private UserService userService;
    public UserServiceProxyImpl(UserService userService){
        this.userService = userService;
    }
    @Override
    public void save() {
        System.out.println("tiancx ");
        userService.save();
    }
}

Test类

@Test
public void testStaticProxy(){
    UserService userService = new UserServiceProxyImpl(new UserServiceImpl());
    userService.save();
}

动态代理

1、编写类介入到bean的生命周期中

package cn.cqie.service;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyProxy implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(final Object o, String s) throws BeansException {
        System.out.println("MyProxy.postProcessBeforeInitialization");
        //使用了jdk的动态代理
        //目标对象的类加载器,目标对象所实现的接口,切面代码的编写
        Object obj = Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("我在前面");
                //找到目标对象的方法
                method.invoke(o, args);
                System.out.println("我在后面");
                return proxy;
            }
        });
        return obj;
    }
    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("MyProxy.postProcessAfterInitialization");
        return o;
    }
}

2、在Spring中配置需要切入的Bean和切入类(MyProxy)

<?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:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">
    <bean id="myProxy" class="cn.cqie.service.MyProxy"/>
    <bean id="userService" class="cn.cqie.service.UserServiceImpl"/>
<!--    deptService是为了测试才加的,看看效果什么样-->
    <bean id="deptService" class="cn.cqie.service.DeptServiceImpl"/>
</beans>

3、后续

再加入一个DeptServiceImpl类试一试

package cn.cqie.service;
public class DeptServiceImpl implements DeptService{
    @Override
    public void save() {
        System.out.println("DeptServiceImpl.save");
    }
}

测试类

@Test
    public void testActiveProxy(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("app.xml");
        UserService userService =  applicationContext.getBean(UserService.class);
//        System.out.println(UserService.class);
        System.out.println(userService.getClass());
        userService.save();
        DeptService deptService = applicationContext.getBean(DeptService.class);
        deptService.save();
    }

Spring的生命周期

bean的生命周期

1.Spring对bean进行实例化,调用bean的构造参数

2.设置对象属性,调用bean的set方法,将属性注入到bean的属性中

3.检查bean是否实现BeanNameAware、BeanFactoryAware、ApplicationContextAware接口,如果实现了这几个接口Spring会分别调用其中实现的方法。

BeanNameAware:setBeanName(String name)方法,参数是bean的ID

BeanFactoryAware:setBeanFactory(BeanFactory bf)方法,参数是BeanFactory容器

ApplicationContextAware:setApplicationContext(ApplicationContext context)方法,参数是bean所在的引用的上下文,如果是用Bean工厂创建bean,那就可以忽略ApplicationContextAware。

4.如果bean是否实现BeanPostProcessor接口,Spring会在初始化方法的前后分别调用postProcessBeforeInitialization和postProcessAfterInitialization方法

5.如果bean是否实现InitalizingBean接口,将调用afterPropertiesSet()方法

6.如果bean声明初始化方法,也会被调用

7.使用bean,bean将会一直保留在应用的上下文中,直到该应用上下文被销毁。

8.检查bean是否实现DisposableBean接口,Spring会调用它们的destory方法

9.如果bean声明销毁方法,该方法也会被调用

AOP核心概念

1、横切关注点

向代码中切入的内容。

2、切面(aspect)

是一个类,包含了若干个横切关注点

3、连接点(joinpoint)

真实被切面切入的方法

4、切入点(pointcut)

想要切入的方法

5、通知(advice)

5种通知:

a、前置通知

b、后置通知

c、异常通知

d、返回通知

e、环绕通知

6、目标对象(Target)

要运行的对象。

7、织入(weave)

将目标对象加入通知,生成代理对象的过程

XML配置实现AOP

1、添加依赖

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>4.3.18.RELEASE</version>
</dependency>

2、编写切面类

package cn.cqie.aop;
import org.aspectj.lang.ProceedingJoinPoint;
/**
 * Description:
 * Author: tiancx
 * Date: Created in 2021/11/20 16:51
 */
public class MyAOP {
//    public void before(){
//        System.out.println("MyAOP.before");
//    }
//    public void after(){
//        System.out.println("MyAOP.after");
//    }
//    public void exception(){
//        System.out.println("MyAOP.exception");
//    }
//    public void afterReturning(){
//        System.out.println("MyAOP.afterReturning");
    //    }
    public Object around(ProceedingJoinPoint joinPoint){
        Object proceed = null;
        try {
            System.out.println("事务开始"); //前置通知
            proceed = joinPoint.proceed(); //执行连接点对应的方法
            System.out.println("事务提交"); //返回通知
        }catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("事务回滚"); //异常通知
        } finally {
            System.out.println("事务关闭"); //后置通知
        }
        return proceed;
    }
}

3、编写service类

package cn.cqie.aop;
import cn.cqie.aop.UserService;
public class UserServiceImpl implements UserService {
    @Override
    public void save() {
        System.out.println("UserServiceImpl.save");
//        System.out.println(1/0);
    }
}

4、配置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:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd" >
    <!--
        AOP的xml配置
        1、添加AOP的命名空间
         xmlns:aop="http://www.springframework.org/schema/aop"
          http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        2、添加需要被Spring管理的实例
        3、添加切面类
    -->
    <bean id="userService" class="cn.cqie.aop.UserServiceImpl"/>
    <bean id="empService" class="cn.cqie.aop.EmpServiceImpl"/>
    <bean id="myAOP" class="cn.cqie.aop.MyAOP"/>
    <!--
       4、aop配置
   -->
    <aop:config >
        <!--
           5、切面配置
            ref="myAOP"关联到切面类
       -->
        <aop:aspect ref="myAOP">
            <!--
               6、配置切入点
           -->
            <aop:pointcut id="pc" expression="execution(* cn.cqie.aop..*(..)) "/>
            <!--
                7、通知配置
                前置
                后置
                异常
                返回
                环绕
            -->
<!--            <aop:before method="before" pointcut-ref="pc"/>-->
<!--            <aop:after method="after" pointcut-ref="pc"/>-->
<!--            <aop:after-throwing method="exception" pointcut-ref="pc"/>-->
<!--            <aop:after-returning method="afterReturning" pointcut-ref="pc"/>-->
            <aop:around method="around" pointcut-ref="pc"/>
        </aop:aspect>
    </aop:config>
</beans>

部分运行结果

AspectJ实现AOP

1、相关类添加注解

比如 @Service

2、编写切面类

package cn.cqie.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
 * Description:
 * Author: tiancx
 * Date: Created in 2021/11/21 12:49
 */
@Aspect  //描述本类为切面类
@Component   //被Spring容器管理
public class MyAOP2 {
    /**
     * execution(* com.woniu..*.*(..))
     * 第一个*表示返回类型
     * 第二个*表示类
     * 第三个*表示方法
     * 第一个..表示根包下类及子包下类
     * 第二个..表示方法的所有参数类型
     */
    @Pointcut("execution(* cn.cqie..*.*(..))")
    public void pointCut(){}
    @Before("pointCut()")
    public void before(){
        System.out.println("MyAOP2.before");
    }
    @After("pointCut()")
    public void after(){
        System.out.println("MyAOP2.after");
    }
    @AfterReturning("pointCut()")
    public void afterReturning(){
        System.out.println("MyAOP2.afterReturning");
    }
    @AfterThrowing("pointCut()")
    public void afterThrowing(){
        System.out.println("MyAOP2.afterThrowing");
    }
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint){
        System.out.println("MyAOP2.around1");
        Object proceed = null;
        try {
           proceed = joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("MyAOP2.around2");
        return proceed;
    }
}

相关文章
|
6月前
|
XML 存储 Java
Spring 6(一)【Spring 入门】
Spring 6(一)【Spring 入门】
|
7月前
|
前端开发 Java Maven
Spring学习笔记
Spring学习笔记
111 0
|
7月前
|
XML Java 数据格式
Spring 学习笔记(二)
Spring 学习笔记(二)
44 0
|
Java 数据库连接 API
|
XML Java 数据库连接
|
XML Java 关系型数据库
|
XML Java 数据格式
day1 Spring学习笔记
day1 Spring学习笔记
61 0