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");

相关推荐
喜欢打篮球的普通人2 分钟前
rust高级特征
开发语言·后端·rust
Ling_suu18 分钟前
Spring——单元测试
java·spring·单元测试
ModelBulider20 分钟前
十三、注解配置SpringMVC
java·开发语言·数据库·sql·mysql
苹果酱056734 分钟前
C语言 char 字符串 - C语言零基础入门教程
java·开发语言·spring boot·mysql·中间件
csucoderlee41 分钟前
eclipse mat leak suspects report和 component report的区别
java·ide·eclipse
代码小鑫1 小时前
A032-基于Spring Boot的健康医院门诊在线挂号系统
java·开发语言·spring boot·后端·spring·毕业设计
训山1 小时前
4000字浅谈Java网络编程
java·开发语言·网络
VertexGeek1 小时前
Rust学习(四):作用域、所有权和生命周期:
java·学习·rust
豌豆花下猫1 小时前
REST API 已经 25 岁了:它是如何形成的,将来可能会怎样?
后端·python·ai
喔喔咿哈哈1 小时前
【手撕 Spring】 -- Bean 的创建以及获取
java·后端·spring·面试·开源·github