IOC模块

  • 什么是ioc

IOC 是Inversion of Control的缩写,多数书籍翻译成“控制反转”

  • IOC的核心是通过set注入来实现控制的反转。
  • 代码案例: 一个useDao的接口。两个实现userDao 接口的实现类,userDaoImpluserDaoMysqlImpl,还有一个userService接口类 来调用userDao类,从容实现service层和dao层的相互调用。

通用类代码

  1. userDao类
public interface UserDao {
    void getUser();
}
  1. userDaoImpl类
public class UserDaoImpl implements UserDao {
    public void getUser() {
        System.out.println("默认获取用户数据");
    }
}
  1. userDaoMysqlImpl类
public class UserDaoMysqlImpl implements UserDao {
    public void getUser() {
        System.out.println("获取MySQL的用户信息");
    }
}
  1. userService类
public interface UserService {
    void getUser();
}

需求: 获取默认的用户信息。
变更需求:获取MySQL用户的信息。
在未使用spring进行管理是,变更需求我们必须修改userServiceImpl的代码,这对程序员来说是不可忍受的。在使用了spring之后,我们需要在service的实现类中添加一个参数userDao,并设置他的set方法。

  1. userServiceImpl类
public class UserServiceImpl implements UserService {
    public void getUser() {
        UserDaoImpl userDao = new UserDaoImpl();
        userDao.getUser();
    }
 }

// 使用spring之后的修改
public class UserServiceImpl implements UserService {
   
    private UserDao userDao  ;

    //set动态注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void getUser() {
        userDao.getUser();
    }


}
  1. 测试类(调用方法)
public class UserDaoTest {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        userService.getUser();

    }
}


//使用spring之后的测试类修改
public class UserDaoTest {
    public static void main(String[] args) {
//
        //拿到spring的容器
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//        需要什么就去哪个beans j就行了
        UserService userService = (UserService) context.getBean("userService");
        userService.getUser();


    }
}
  1. 使用spring需要spring的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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="mysqlImpl" class="com.mei.dao.UserDaoMysqlImpl">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <bean id="impl" class="com.mei.dao.UserDaoImpl">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <bean id="userService" class="com.mei.service.UserServiceImpl">
        <!--
        ref 引用spring 容器中创建的对象
        value 是具体的值,基本数据类型
        -->
        <property name="userDao" ref="mysqlImpl"></property>
    </bean>
    <!-- more bean definitions go here -->

</beans>

在使用spring之后,出现这种需求的变更,便需要需改spring的xml配置文件即可解决。使用set的注入之后便把调用的权力从写死的程序中转移到了调用者的配置文件中。

spring配置文件使用

  1. IOC创建对象的方法
  • 使用无参的构造方法
<bean id="mysqlImpl" class="com.mei.dao.UserDaoMysqlImpl">
        <!-- collaborators and configuration for this bean go here -->
    </bean>
  • 使用有参构造方法
    - 下标构建 :
<bean id="user" class="com.mei.pojo.User">
        <constructor-arg  index="0" value="meifeng"></constructor-arg>
    </bean>
- 参数类型匹配(不建议使用,存在同类型不好区分)
<bean id="user" class="com.mei.pojo.User">
        <constructor-arg type="java.lang.String" value="qingjiang"></constructor-arg>
    </bean
-  通过参数名来构建
<bean id="user" class="com.mei.pojo.User">
        <constructor-arg name="name" value="卿家"></constructor-arg>
    </bean>

总结:在配置文件加载的时侯,容器中的管理的对象就已经被初始化了!不论是否已经使用

spring的配置参数

  • 别名
<alias name="user" alias="useralias" />
  • bean的配置
<!--
        id: bean 的唯一标识,也相当与我们学的对象的名字
        class: bean 对象所对应的全限定名:包名+类名
        name: 也是别名,可以去多个别名
        scope: 范围
    -->
    <bean id="user" class="com.mei.pojo.User" name="userCopy; userCopy1">
        <constructor-arg name="name" value="卿家"></constructor-arg>
    </bean>
  • import
    这个import 一般,一般用与团队开发使用,它可以将多个配置文件合并导入。假设,现在项目中有多个人开发,不同的类需要注册在不同的bean中,我们可以利用import 将所有人的bean 中合并。

依赖注入

  • 构造器注入
  • set注入
    依赖注入
    依赖:bean 对象的创建依赖与容器
    注入:bean 对象中的所有属性由容器来注入
  • 拓展注释

bean的自动装配

  • 自动装配是spring满足bean 依赖的一种方式
  • spring 会在上下文中自动寻找,并自动的给bean装配属性
    在spring中的三种自动装配方式
  1. 在xml中显示的配置
  2. 在Java中显示的配置
  3. 隐式的自动装配bean(重点)
    测试
    byName的自动装配
    总结: byName 的时候需要保证所有bean的id唯一并且这个bean需要和自动注入的set方法的值一致
    byType的时候需要保证所有bean的类型唯一并且这个bean需要和自动注入的属性类型一致
  4. 使用注解自动装配
-   使用注解须知
   导入约束 context 约束
   配置注解的支持
  • @Autowired 注解在属性上
    使用autowired 我们可以不用编写set方法,前提是你的这个自动装配的属性在IOC容器中存在,且符合byName 的规则
    @nullable 表示字段可以为空

@Reource 与@Autowired 的注解

  1. 都是用来自动注解,都可以放在属性字段上
  2. @Autowired 是通过byName
  3. @Resource 是先通过ByName,在通过ByType

AOP代理
为什么要学习代理模式: 因为这个是spring的Aop的底层,(Spring AOP 和SpringMVC)
代理模式的分类:
静态代理

动态代理

  1. 基于接口的动态代理,基于类的动态代理
  2. 基于接口----JDK 的动态代理
  3. 基于类 ----cglib
    java 字节码实现 : javasist
    Proxy 和 InvocationHandle

AOP在Spring配置中的使用

需求:在已经写好的操作user类的方法上注入添加操作日志信息

AOP配置的三种方式

  • 使用原生的spring API 配置
//后日志
public class AfterLog implements AfterReturningAdvice {
    public void afterReturning(Object returnValue, Method method, Object[] ages, Object target) throws Throwable {
        System.out.println("执行力"+method.getName()+"方法,返回结果为"+returnValue);
    }
}
//前日志
public class Log implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行");
    }
}
<!--指定要扫描的包,这个包下的主句就会生效-->
    <bean id="userService" class="com.mei.service.UserServiceImpl"/>
    <bean id="log" class="com.mei.log.Log"></bean>
    <bean id="afterLog" class="com.mei.log.AfterLog"/>
    <!--方式一:使用原生的spring API  接口-->
    <!--配置aop-->
    <aop:config>
        <!--配置一个切人点: expression:表达式 execution(要执行的位置!******)-->
        <aop:pointcut id="pointcut" expression="execution(* com.mei.service.UserServiceImpl.*(..))"/>
        <!--执行环绕增强-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
  • 自定义类
public class DiyPointCut {
    public void before(){
        System.out.println("--------前---------");
    }
    public  void after(){
        System.out.println("------------后----------");
    }
}
<bean id="diy" class="com.mei.diy.DiyPointCut"/>
    <aop:config>
       <aop:aspect ref="diy">
           <!--切人点-->
           <aop:pointcut id="point" expression="execution(* com.mei.service.UserServiceImpl.*(..))"/>

           <!--通知-->
           <aop:after method="after" pointcut-ref="point"></aop:after>
           <aop:before method="before" pointcut-ref="point"/>
       </aop:aspect>
    </aop:config>
  • 注解
@Aspect
public class AnnocationPonitCut {

    @Before("execution(* com.mei.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("=======前==============");
    }
    @After("execution(* com.mei.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("==============后==========");
    }
    @Around("execution(* com.mei.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("前");
        joinPoint.proceed();
        System.out.println("后");

    }

}
<bean id="annPonitCut" class="com.mei.diy.AnnocationPonitCut"/>
    <!--方法三: 注解-->
    <!--开启注解-->
    <aop:aspectj-autoproxy/>