spring入门aop和ioc

文章目录

spring分层架构

表现层

springmvc
2.

服务层(业务层)

spring ioc
3.

持久层

mybatis

mybatis plus

hibernite

互联网项目,多ssm结构

spring核心

ioc(控制反转)

ioc将对象的创建权利交给spring框架,底层实际上是使用反射实现的。降低程序的耦合度

1)接下来是代码示例:
  1. 创建一个空的maven项目

  2. 引入一些基本依赖

xml 复制代码
<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

    </dependencies>
  1. 准备实体类

    java 复制代码
    // 创建一个接口
    public interface UserService {
        public void hello();
    }
    // 创建一个实体类
    public class UserServiceImpl implements UserService {
        @Override
        public void hello() {
            System.out.println("Hello, world!");
        }
    }
  2. 准备配置文件

    xml 复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="us" class="实体类的路径"></bean>
    </beans>
  3. 在test中测试

    java 复制代码
    // 常规方法
        @Test
        public void testUser() {
            // TODO: write test cases for UserService
            UserService userService = new UserServiceImpl();
            userService.hello();
        }
    // 基于ioc容器管理的方法,ioc是一个map key是对象的标识,value是ioc创建的对象
        @Test
        public void run1() {
            // 创建spring ioc工厂
            ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
            // 获取bean
            UserService userService = (UserService) ac.getBean("us");
            userService.hello();
        }

上面就是一个关于ioc容器的示例

2)ioc容器的使用过程

ApplicationContext接口,这个工厂接口,使用这个接口就可以获得相应的Bean对象,该对象下有两个实现类

  1. ClassPathXmlApplicationContext:加载类路径下的spring配置文件(常用)
  2. FileSystemXmlApplicationContext:加载本地磁盘下的spring配置文件(让项目和配置文件分离管理,不常用)
3)ioc中的bean管理
  1. id属性:bean的别名,取名要求:必须要字母开头,可以使用数字,连字符,下划线,字母,不能出现特殊字符
  2. class属性:bean对象的全路径
  3. scope属性: bean对象的作用范围
    1. singleton:单例(默认)生命周期和配置文件一样
    2. prototype:多例,不是加载配置文件时创建,而是在获取实例对象时创建
    3. request: 多例,不常用,应用于web项目中,每个请求都会创建一个新的实例对象
    4. session:多例,不常用,应用于web项目中,向一个http session中共享一个实例
  4. init-method:bean对象创建时可以配置一个指定的方法自动调用
  5. destory-method:bean对象销毁时可以配置一个指定的方并自动调用
4)实例化bean的三种方式
  1. 默认是无参的构造方法

    xml 复制代码
        <bean id="us" class="实体类的路径"></bean>
  2. 静态工厂实例化方法(好处是可以自己编写业务逻辑)

    准备一个静态工厂类

    java 复制代码
    public class StaticFactory {
        public static UserService createUser() {
            // 编写业务逻辑
            // ......
            return new UserServiceImpl();
        }
    }

    在xml配置文件中使用

    xml 复制代码
        <bean id="us1" class="com.qc.util.StaticFactory" factory-method="createUser"></bean>
  3. 实例化工厂实例化方式

    准备一个可以实例化的类

    java 复制代码
    public class DFactory {
        public  UserService createUser() {
            // 编写业务逻辑
            return new UserServiceImpl();
        }
    }

    在xml配置文件中使用

    xml 复制代码
        <bean id="factory" class="com.qc.util.DFactory"></bean>
        <bean id="us2" factory-bean="factory" factory-method="createUser"></bean>

aop(面向切面开发)

定义

是一种编辑的范式,是OOP的延续,也是Spring框架中函数编程的一种衍生范式,利用AOP可以对业务的各个部分进行隔离,从而似的业务逻辑各部分之间的耦合度降低,提高了程序的重用性,同时提高了开发的效率,AOP采用横向抽取机制,取代了传统纵向继承体系。

优势

  1. 运行期间,不修改源代码的情况下,对已有的方法进行增强,减少重复代码
  2. 提高开发效率
  3. 方便维护

AOP底层原理

  1. 如果使用接口,则使用JDK动态代理技术,如果没有使用接口,使用的是继承则是cglib代理

AOP相关的术语

  1. Joinpoint(连接点)所谓连接点是指那些被连接到的点,在spring中,这些带点指的是方法,因为spring只支持方法类型的节点
  2. Pointcut(切入点)所谓切入点是我们要对哪些Joinpoint进行拦截的定义
  3. Advice(通知\通知)所谓通知就是指,拦截到Joinpoint之后所要做的情况就就是通知,通知分为,前置通知,后置通知,异常通知,最终通知,环绕通知(切面类中要完成的功能)
  4. Target(目标对象)代理的目标对象
  5. Weaving(织入)是指把增强应用到目标对象来创建新的代理对象的过程
  6. Proxy(代理)一个类被AOP织入增强后,就产生一个结果代理类
  7. Aspect(切面)是切入点+通知的结合,是自己编写和配置

AOP入门

  1. 导入坐标依赖

    pom.xml 复制代码
    <dependency>
                <groupId>aopalliance</groupId>
                <artifactId>aopalliance</artifactId>
                <version>1.0</version>
            </dependency>
            <!--Spring Aspects-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>5.0.2.RELEASE</version>
            </dependency>
            <!--aspectj-->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.3</version>
            </dependency>
    applicationContext.xml 复制代码
    <?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: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/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">
    </beans>
  2. 编写spirng配置文件中AOP的配置部分

    applicationContext.xml 复制代码
        <!--    bean管理-->
        <bean id="us" class="com.qc.service.impl.UserServiceImpl"/>
        <bean id="myAspect" class="com.qc.util.MyAspect"/>
    
        <!--    配置aop-->
        <aop:config>
            <!--        配置切面-->
            <aop:aspect ref="myAspect">
                <!--            前缀通知-->
                <aop:before method="log1" pointcut="execution(public void com.qc.service.impl.UserServiceImpl.save())"/>
                <!--            后置通知-->
                <aop:after-returning method="log2"
                                     pointcut="execution(public void com.qc.service.impl.UserServiceImpl.save())"/>
                <!--            异常通知-->
                <aop:after-throwing method="log3"
                                    pointcut="execution(public void com.qc.service.impl.UserServiceImpl.save())"/>
                <!--            最终通知-->
                <aop:after method="log4"
                           pointcut="execution(public void com.qc.service.impl.UserServiceImpl.save())"/>
    
                <!--            环绕通知-->
                <aop:around method="aroundLog"
                            pointcut="execution(public void com.qc.service.impl.UserServiceImpl.save())"/>
            </aop:aspect>
        </aop:config>
    java 复制代码
    import org.aspectj.lang.ProceedingJoinPoint;
    
    public class MyAspect {
        // 自定义切面类 = 切入点+通知
        //通知
        public void log1() {
            System.out.println("前置增强的");
        }
    
        public void log2() {
            System.out.println("后置增强的");
        }
    
        public void log3() {
            System.out.println("异常增强的");
        }
    
        public void log4() {
            System.out.println("最终增强的");
        }
    
    
        public void aroundLog(ProceedingJoinPoint point) {
            try {
                log1();
                point.proceed(); // 目标方法调用
                log2();
            } catch (Throwable e) {
                e.printStackTrace();
                log3();
            } finally {
                log4();
            }
        }
    }

    注意环绕通知使用的接口

通知类型

  1. 前置通知:目标方法执行前进行增强
  2. 后置通知:目标方法执行后进行增强
  3. 异常通知:目标方法出现异常后进行增强
  4. 最终通知:目标方法无论是否异常都进行增强
  5. 环绕通知:目标方法执行前后,都进行增强,不过需要自己书写

切入点表达式

  • execution([修饰符] 返回值 包名.类名.方法名(参数))
  • 修饰符可以省略不写
  • 返回值类型不能省略,根据方法来编写返回值,可以用星号来代替
  • 包名类型方法名是不能省略的,但是可以用星号来代替,也可以部分代替
  • 参数如果是一个可以用星号来代替,如果是多个可以使用两个点

因此比较通用的表达式:

execution( com.qc .*.Service.save(...))

aop注解开发

给切面添加@Aspect,编写增强的方法,使用通知类型注解声明

xml 复制代码
    <!--    开启注解扫描-->
    <context:component-scan base-package="com.qc"/>

    <!--    开启自动代理-->
    <aop:aspectj-autoproxy/>
java 复制代码
@Aspect
@Component
public class MyAspect {
    // 自定义切面类 = 切入点+通知
    //通知
    @Before("execution(* com.qc.*.*.*ServiceImpl.save(..))")
    public void log1() {
        System.out.println("前置增强的");
    }

    @AfterReturning("execution(* com.qc.*.*.*ServiceImpl.save*(..))")
    public void log2() {
        System.out.println("后置增强的");
    }

    @AfterThrowing("execution(* com.qc.*.*.*ServiceImpl.save*(..))")
    public void log3() {
        System.out.println("异常增强的");
    }

    @After("execution(* com.qc.*.*.*ServiceImpl.save*(..))")
    public void log4() {
        System.out.println("最终增强的");
    }

    @Around("execution(* com.qc.*.*.*ServiceImpl.save*(..))")
    public void aroundLog(ProceedingJoinPoint point) {
        try {
            log1();
            point.proceed(); // 目标方法调用
            log2();
        } catch (Throwable e) {
            e.printStackTrace();
            log3();
        } finally {
            log4();
        }
    }
}

在每个方法上使用注解进行配置,和配置文件类似

通知类型注解:

  1. @Before 前置注解
  2. @AfterReturning 后置注解
  3. @AfterThrowing 异常注解
  4. @After 最终注解
  5. @Round 环绕注解

注意:在配置文件中开启自动代理

aop纯注解开发

@EnableAspectJAutoProxy 开启自动代理
3.

Di(依赖注入)

依赖注入:在spring框架负责创建bean对象时,动态的将对象注入到其他的bean对象中

1)属性的set方法注入值的方式
  1. 声明变量并在需要依赖注入的地方设置set方法

  2. 在xml文件中配置该变量的值

    xml 复制代码
        <bean id="us" class="com.qc.service.impl.UserServiceImpl">
            <property name="userDao" ref=""></property>
            <property name="name" value=""></property>
        </bean>

    参数说明:如果property中的是一个简单类型(基本类型和字符串),那么就使用value,否则就使用ref

2)构造方法赋值的方法
  1. 在需要的地方添加构造方法

  2. 在配置文件中使用带参数的构造方法传参

    xml 复制代码
        <bean id="userDao" class="com.qc.dao.impl.UserDaoImpl"></bean>
        <bean id="us" class="com.qc.service.impl.UserServiceImpl">
            <constructor-arg name="userDao" ref="userDao"></constructor-arg>
        </bean>
  3. 其他类型的参数传参

    准备一个java类

    java 复制代码
    public class CollectionBean {
        private String[] strs;
        private List<String> list;
        private Map<String, String> map;
        private Properties properties;
    
        public Properties getProperties() {
            return properties;
        }
    
        public void setProperties(Properties properties) {
            this.properties = properties;
        }
    
        public Map<String, String> getMap() {
            return map;
        }
    
        public void setMap(Map<String, String> map) {
            this.map = map;
        }
    
        public String[] getStrs() {
            return strs;
        }
    
        public List<String> getList() {
            return list;
        }
    
        public void setList(List<String> list) {
            this.list = list;
        }
    
        public CollectionBean() {
        }
    
        public void setStrs(String[] strs) {
            this.strs = strs;
        }
    
        public CollectionBean(String[] strs) {
            this.strs = strs;
        }
    }
    1. 不可变数组

      xml 复制代码
      <bean id="co" class="com.qc.service.CollectionBean">
              <property name="strs">
                  <array>
                      <value>小美</value>
                      <value>小张</value>
                      <value>小王</value>
                  </array>
              </property>
          </bean>
    2. 可变集合

      xml 复制代码
          <bean id="co" class="com.qc.service.CollectionBean">
              <property name="list">
                  <list>
                      <value>张三</value>
                      <value>李四</value>
                      <value>王五</value>
                  </list>
              </property>
          </bean>
    3. map集合

      xml 复制代码
      <bean id="co" class="com.qc.service.CollectionBean">
              <property name="map">
                  <map>
                      <entry key="name" value="zhangsan"></entry>
                      <entry key="age" value="18"></entry>
                  </map>
              </property>
          </bean>
    4. 其他类型

      xml 复制代码
        <bean id="co" class="com.qc.service.CollectionBean">
              <property name="properties">
                  <props>
                      <prop key="username">zhangsan</prop>
                      <prop key="password">1234</prop>
                  </props>
              </property>
          </bean>

多配置文件

  1. 在配置文件中使用

    xml 复制代码
    <import resource="applicationContext.xml"></import>
  2. 创建工厂时直接加载多个配置文件

    java 复制代码
            ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext1.xml");

复制代码
                <props>
                     <prop key="username">zhangsan</prop>
                     <prop key="password">1234</prop>
                 </props>
             </property>
         </bean>
     ```

多配置文件

  1. 在配置文件中使用

    xml 复制代码
    <import resource="applicationContext.xml"></import>
  2. 创建工厂时直接加载多个配置文件

    java 复制代码
            ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext1.xml");

相关推荐
Asthenia04121 小时前
Spring扩展点与工具类获取容器Bean-基于ApplicationContextAware实现非IOC容器中调用IOC的Bean
后端
bobz9651 小时前
ovs patch port 对比 veth pair
后端
Asthenia04121 小时前
Java受检异常与非受检异常分析
后端
uhakadotcom2 小时前
快速开始使用 n8n
后端·面试·github
JavaGuide2 小时前
公司来的新人用字符串存储日期,被组长怒怼了...
后端·mysql
bobz9652 小时前
qemu 网络使用基础
后端
Asthenia04122 小时前
面试攻略:如何应对 Spring 启动流程的层层追问
后端
Asthenia04122 小时前
Spring 启动流程:比喻表达
后端
Asthenia04123 小时前
Spring 启动流程分析-含时序图
后端
ONE_Gua3 小时前
chromium魔改——CDP(Chrome DevTools Protocol)检测01
前端·后端·爬虫