Spring思想理解

Spring思想养成

为了解决企业级的轻量级开发Spring,减少模块与模块之间的耦合性——具体就是帮助开发人员创建类对象,管理对象之间的关系

核心技术

在这里插入图片描述
AOP
在这里插入图片描述
核心容器(存储的是java对象)
在这里插入图片描述
在这里插入图片描述

IoC(Invasion of Control)控制反转 思想

把对象的创建,赋值,管理工作交给代码之外的容器实现,也就是对象的创建是其他外部资源完成的
控制:创建对象,对象属性的赋值,对象之间的关系管理。
反转:把创建对象的权限转移给代码之外的容器处理实现,容器代替开发人员
正转:由开发人员在代码中,使用new 构造方法创建对象,开发人员主动管理对象。

为什么要使用IoC:减少对代码的改动,也能实现不同的功能 (解耦合)

容器:可以是一个服务器软件,也可以是一个框架(spring)

java中创建对象的方式:

  1. 构造方法
  2. 反射
  3. 序列化
  4. IoC
  5. 克隆
  6. 动态代理

IoC的技术实现
DI是IoC的技术实现
DI(Dependency Injection)依赖注入 只需要在程序中提供要使用的对象名称即可,至于对象何时在容器中创建,赋值,查找都由容器内部实现
spring使用的di来实现ioc功能,spring底层创建对象,使用的是反射机制

IoCDemo

创建maven项目
导入依赖

<!--    测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
<!--    spring-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.7.RELEASE</version>
    </dependency>
  </dependencies>

创建接口和实现类

package com.dhf.service;

public interface DoService {
    void doSome();

}


package com.dhf.service.impl;

import com.dhf.service.DoService;

public class DoServiceImpl implements DoService {
    @Override
    public void doSome() {
        System.out.println("执行了doSome方法---------");
    }
}

使用主动创建对象的方法

   @Test
    public void iocTest(){
        DoService doService = new DoServiceImpl();
        doService.doSome();
    }

能正常调用对象的方法。

使用IoC控制反转技术容器创建对象
先配置spring容器的配置文件

<?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">
<!--
   spring 的配置文件
     1.beans 根标签,java的对象都转化成bean放在beans中
     2.spring-beans.xsd 约束文件
-->
<!--
   声明bean,创建某个对象
   id:对象的自定义名称,唯一
   class:类的全限定名称(不能是接口,spring使用的是反射机制创建对象,必须使用类)

   spring完成的是 DoService doService = new DoServiceImpl();
   spring把创建好的对象放入map中,spring框架中有一个map存放对象的
      springMap.put(id的值,对象)
      
   一个bean声明一个对象
-->
    <bean id="doService" class="com.dhf.service.impl.DoServiceImpl"/>
</beans>

spring的使用

    @Test
    public void iocTest(){
        //使用ApplicationContext 创建容器对象。
        ApplicationContext context =
       new ClassPathXmlApplicationContext("spring-config.xml");
       //通过context 取出里面的id对应的bean
        DoService doService = (DoService) context.getBean("doService");
        doService.doSome();
    }

得到一样的结果,这就是通过容器来创建对象的全过程。

注入分类
  1. set注入(设置注入);spring调用类的set方法,在set方法可以实现属性的赋值。
<!--    给属性赋值(注入就是赋值)
        简单类型:java的八个基本类型和String都是简单类型
        1.set注入 spring只是调用了set方法
          1)简单类型注入
             <bean class="xxx" id="xxxx">
                  <property name="属性1" value="值"/>
                  <property name="属性2" value="值"/>
             </bean>
           2)引用类型注入
              <bean class="xxx" id="xxxx">
                  <property name="属性1" ref="其他bean id"/>
              </bean>
-->
    <bean class="pojo.Student" id="student" scope="singleton">
        <property name="name" value="小猪"/>
        <property name="age" value="1"/>
    </bean>

还可以在java程序中加入注解赋值(可以加在属性上 也可以加在set方法上面)同时在spring配置文件中需要加入< context:annotation-config /> 启动注解

(1)< context:annotation-config />:仅能够在已经在已经注册过的bean上面起作用。对于没有在spring容器中注册的bean,它并不能执行任何操作。

(2)< context:component-scan base-package=“XX.XX”/> :除了具有上面的功能之外,还具有自动将带有@component,@service,@Repository等注解的对象注册到spring容器中的功能。

思考2:如果同时使用这两个配置会不会出现重复注入的情况呢?
答案:因为< context:annotation-config />和 < context:component-scan>同时存在的时候,前者会被忽略。如@autowire,@resource等注入注解只会被注入一次!

    private String name;

    @Value("3")
    private Integer age;

    @Value("小猪")
    public void setName(String name) {
        this.name = name;
    }
    
    public void setAge(Integer age) {
        this.age = age;
    }
  1. 构造方法注入:spring调用类的有参构造方法,创建对象在构造方法中赋值
<!--
        2.构造注入 spring调用有参构造方法
          使用<constructor-arg>标签 一个标签表示构造方法一个参数 value
          name:构造方法的形参名
          index:参数位子   0,1,,,,,
          value:形参是简单类型就用value
          ref:形参是引用类型就用ref
-->
    <bean class="pojo.Student" id="student" scope="singleton">
<!--        <property name="name" value="小猪"/>-->
<!--        <property name="age" value="1"/>-->
        <constructor-arg name="name" value="小猪"/>
        <constructor-arg name="age" value="4"/>
    </bean>
注解创建对象

使用注解的步骤

  1. 加入maven依赖spring-context,在加入spring-context同时加入了spring-aop的依赖
  2. 在类中加入spring的注解(
    @Component,通用的 创建对象
    @Repository,持久层 dao访问数据库
    @Service,业务层 service添加业务,事务管理
    @Controller,控制层 controller接收用户提交的参数,显示请求的处理结果
    @Value,简单类型赋值
    @Autowried,spring框架提供的引用类型赋值,默认byType
    @Resource ,jdk提供的引用类型赋值,默认byName
  3. 在spring配置文件中加入组件扫描标签,说明注解在你的项目中的位置
    < context:component-scan base-package="***" />

AOP面向切面编程

底层就是动态代理(可参考链接: jdk动态代理的理解.)可以使用jdk,sglib两种代理。

AOP就是动态代理的规范化,把动态代理的实现步骤,方式定义好了,让开发人员使用统一 的方式使用动态代理。

动态代理的作用
1)在目标资源不改变的情况下,增加功能。
2)减少代码的重复。
3)专注业务逻辑代码
4)解耦合,让业务功能和日志、事务等非业务功能分离。

理解面向切面编程
1)需要再分析项目功能时,找出切面。
2)合理安排切面的执行时间(在目标方法前还是方法后)。
3)合理安排切面的执行位置在哪个类,哪个方法增强功能。

术语:
1)Aspect:切面,表示增强的功能,完成一个非业务功能,常见的切面功能,日志,事务,权限验证,参数检查,统计信息。
2)JionPoint:连接点,连接切面与业务方法的位置,就是某类的业务方法。
3)Pointcut:切入点,指多个连接点的集合。
4)目标对象:给哪个类的方法添加功能,这个类就是目标对象
5)Advice:通知,通知表示切面功能执行的时间。在目标方法之前还是之后还是环绕。
一个切面有三个要素:
1)切面的功能代码,切面干什么。
2)切面的执行位置,Piontcut表示。
3)切面的执行时间,Advice表示。

aop的实现

aspectJ:一个开源专门做aop的框架
aspectJ实现aop的两种方式:
1)xml 的配置文件 :主要用于配置全局事务
2)注解 比较广泛 aspectJ有五个注解

1)切面的执行时间 advice(通知,增强)aspectJ有五个注解
1. @Before
2. @AfterReturning
3. @Around
4. @AfterThrowing
5. @After
2)表示切面的位置,常用的语法

 五种固定语法.".."出现在类名中时,后面必须加*,表示包、子包下的所有类)
1. 指定切入点为任意公共方法:
execution(public * * (..))
2. 指定切入点为”set”开头的任意方法:
execution(* set*(..))
3. 指定切入点为所有包下的service子包下的所有类(接口)中所有方法:
execution(* *..service.*.*(..) )
4. 指定切入点为service包下的任意类的任意方法:
execution(* com.xyz.service.*.*(..))
5. 指定切入点为service包和子包下的任意类的任意方法:
execution(* com.xyz.service..*.*(..))
使用xml配置文件 动态代理Demo
定义目标类接口和实现类
package com.dhf.service;
public interface AspectJservice {

    void  doSome(String name);
}


package com.dhf.service.imp;
import com.dhf.service.AspectJservice;

public class AspectJserviceImpl implements AspectJservice {
    @Override
    public void doSome(String name) {
        System.out.println(name+" 调用了这个类");
    }
}

定义切面类(增强功能集合)
package com.dhf.advice;
import java.util.Date;

public class Aspectadvice {

    public void beferDate(){
        System.out.println("系统当前时间: "+new Date());
    }

}
applicationconfig.xml配置文件(使用配置文件实现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: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/aop 
       https://www.springframework.org/schema/aop/spring-aop.xsd">

<!--      创建service目标类对象-->
    <bean id="sspectJservice" class="com.dhf.service.imp.AspectJserviceImpl" />

<!--    创建切面类对象-->
    <bean class="com.dhf.advice.Aspectadvice" id="aspectadvice"/>

<!--    配置aop-->
    <aop:config >
<!--  定义切面                干什么-->
        <aop:aspect ref="aspectadvice" id="myaspect">
<!--  定义切入点               在哪干-->
            <aop:pointcut id="point" expression="execution(* *..service.*.doSome(..))"/>
<!--  定义切入方法的哪个位置     什么时间-->
            <aop:before method="beferDate" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
    
</beans>
可使用注解的方式代替 aop的配置

在切面类上完成所有的配置

package com.dhf.advice;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import java.util.Date;

/**
 * @Aspect  告诉容器 这是一个切面类
 */
@Aspect
public class Aspectadvice {
    /**
     * @Before  告诉容器 这是前置通知  
     * execution(* *..service.imp.AspectJserviceImpl.doSome(..))  前置通知的切入点
     */
    @Before("execution(* *..service.imp.AspectJserviceImpl.doSome(..))")
    public void beferDate(){
        System.out.println("系统当前时间: "+new Date());
    }

}

在配置文件做修改

<?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: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/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">

<!--      创建service目标类对象-->
    <bean id="sspectJservice" class="com.dhf.service.imp.AspectJserviceImpl" />

<!--    创建切面类对象-->
    <bean class="com.dhf.advice.Aspectadvice" id="aspectadvice"/>

<!--    自动代理-->
   <aop:aspectj-autoproxy/>
</beans>

最终的结果都是
在这里插入图片描述

注意:

切面的同时方法中可以有参数:JoinPoint

joinPoint :业务方法,要加入切面的业务方法
作用:
1.可以在通知方法中获取方法执行的信息,例如方法名称,方法实参
2. 如果在切面中需要用到方法的信息可以加入JionPiont
3. 这个参数是框架赋值的,必须是参数中的第一个位置。

    /**
     * @Before  告诉容器 这是前置通知
     * execution(* *..service.imp.AspectJserviceImpl.doSome(..))  前置通知的切入点
     */
    @Before("execution(* *..service.imp.AspectJserviceImpl.doSome(..))")
    public void beferDate(JoinPoint jp){
        //获取方法的完整定义
        System.out.println("方法的完整定义:"+jp.getSignature());
        //获取方法的名称
        System.out.println("方法的名称: "+jp.getSignature().getName());
        Object[] args = jp.getArgs();
        for (Object obj:args){
            System.out.println("参数="+obj);
        }
        System.out.println("系统当前时间: "+new Date());
    }

}

在这里插入图片描述

<!--    自动代理 即使目标类有接口,也使用Cglib  执行时效率高一些-->
     <aop:aspectj-autoproxy proxy-target-class="true"/>

持续更新中…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值