spring IOC、AOP整理

Spring5

内容


  • IOC容器

    • 什么是IOC

    • IOC底层原理

    • IOC接口(beanFactory)

    • IOC操作Bean管理(基于xml)

    • IOC操作Bean管理(基于注解)

  • AOP

IOC

  1. 什么是Ioc
    控制反转,把对象的创建和对象之间的关系交给spring进行管理
    目的:解耦,是耦合度降低

  2. Ioc底层原理

    xml解析、工厂模式、反射
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SHHGfTbT-1654580557502)(ddddd\图1.png)]
    在这里插入图片描述

  3. BeanFactory接口

    • IOC思想基于IOC容器完成,IOC容器底层就是对象工厂

    • Spring 提供ioc容器的两种方式:(两个接口)

      • BeanFactory:IOC容器的基本实现,是spring内部使用的接口,不提供给开发人员使用 加载配置文件的时候不会创建对象,在使用对象的时候会创建。

      • ApplicationContext BeanFactory接口的子接口,提供更强大的功能,一般由开发人员使用,加载配置文件的时候就会创建对象。

      • ApplicationContext有实现类

        • CalssPathXmlApplicationContext
        • FileSystemXmlApplicationContext

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wi2TzUHY-1654580557503)(C:\Users\StarLee\AppData\Roaming\Typora\typora-user-images\image-20220518225732850.png)]

选中接口 +F4出现该接口的层级结构

hierarchy ˈhaɪərɑːki’ 等级层级

ClassPathXmlApplicationContextFileSystemXmlApplicationContext的区别

classpath:前缀是不需要的,默认就是指项目 src 目录下的配置文件

 ApplicationContext factory = new ClassPathXmlApplicationContext("classpath:appcontext.xml");
 ApplicationContext factory = new ClassPathXmlApplicationContext("appcontext.xml");

FileSystem: 即系统文件路径,文件的目录
1.没有盘符的是项目工作路径,即项目的根目录;
2.有盘符表示的是文件绝对路径.

ApplicationContext factory = new FileSystemXmlApplicationContext("classpath:appcontext.xml");
ApplicationContext factory = new FileSystemXmlApplicationContext("file:F:/workspace/example/src/appcontext.xml");

**Bean管理是指两个操作 **

  • Bean的创建
  • bean的注入

bean管理的两种方式

  • 基于xml配置
  • 基于注解

  1. IOC操作bean管理(基于xml配置)

    • 基于xml配置方式

      <--配置User对象创建-->
      <bean id="user" class="com.atguigu.spring5.User"></bean>
      
      1. 在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
      2. 在 bean 标签有很多属性,介绍常用的属性
        • id 属性:唯一标识
        • class 属性:类全路径(包类路径)
    • 基础xml方式注入属性

      • DI 依赖注入(set注入、构造器注入等)

             <!--属性值包含特殊符号
                    1<>进行转义 &lt; &gt;
                    2 把带特殊符号内容写到CDATA
                -->
                    <![CDATA[<=WEWR]]>
                <property name="address">
                    <value><![CDATA[<<南京>>]]></value>
                </property>
        
    • Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)

      • 普通 bean:在配置文件中定义 bean 类型就是返回类型

      • 工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样

        • 第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean

        • 第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型

          public class MyBean implements FactoryBean<Course> {
          
              //定义返回bean
              @Override
              public Course getObject() throws Exception {
                  Course course = new Course();
                  course.setCname("abc");
                  return course;
              }
          
              @Override
              public Class<?> getObjectType() {
                  return null;
              }
          
              @Override
              public boolean isSingleton() {
                  return false;
              }
          }
          
          
          <bean id="myBean" 		class="com.atguigu.spring5.factorybean.MyBean">
          </bean>
              
          @Test
          public void test3() {
           ApplicationContext context =
           new ClassPathXmlApplicationContext("bean3.xml");
           Course course = context.getBean("myBean", Course.class);
           System.out.println(course);
          }
          
    • IOC操作Bean管理(Bean的作用域)

      • 在spring中,设置bean的创建是单实例还是多实例
      • 在spring中,默认情况下,bean是单例的
      • 如何设置是单实例还是多实例
        • 在 spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例
        • scope 属性值
          • 第一个值 默认值,singleton,表示是单实例对象
          • 第二个值 prototype,表示是多实例对象
      • singleton和prototype区别
        • singleton是单实例,prototype是多实例
        • 设置scope为single时,加载spring配置文件时就会创建单实例对象,
          设置scope为prototype时,不是在加载 spring 配置文件时候创建对象,在调用getbean 方法的时候创建多实例对象
    • IOC操作bean管理(bean的生命周期)

      • 生命周期 :从对象的创建到对象的销毁的过程

      • bean的生命周期:

        1. 通过构造器创建bean实例(无参构造器)
        2. 为bean的属性设置值和对其它bean的引用(调用set方法)
        3. 调用bean的初始化方法(需要进行配置初始化的方法)
        4. bean使用(对象获取到了)
        5. 当容器关闭时,调用bean的销毁方法(需要配置销毁方法)
      • 演示bean的生命周期

        <bean id="orders" class="com.atguigu.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
                <property name="oname" value="手机"></property>
         </bean> 
        
        public class Orders {
        
            //无参数构造
            public Orders() {
                System.out.println("第一步 执行无参数构造创建bean实例");
            }
        
            private String oname;
            public void setOname(String oname) {
                this.oname = oname;
                System.out.println("第二步 调用set方法设置属性值");
            }
        
            //创建执行的初始化的方法
            public void initMethod() {
                System.out.println("第三步 执行初始化的方法");
            }
        
            //创建执行的销毁的方法
            public void destroyMethod() {
                System.out.println("第五步 执行销毁的方法");
            }
        }
        
        @Test
        public void testBean4() {
            ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("bean4.xml");
            Orders orders = context.getBean("orders", Orders.class);
            System.out.println("第四步 获取创建bean实例对象");
            System.out.println(orders);=
        
                //手动让bean实例销毁
                context.close();
        }
        

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WQPGjne1-1654580557503)(C:\Users\StarLee\AppData\Roaming\Typora\typora-user-images\image-20220519220328325.png)]

      • baen的后置处理器bean的生命周期有七步

        1. 通过构造器创建bean的实例(无参构造器)
        2. 为bean的属性设置值和对其它bean的引用(调用set方法)
        3. 把bean实例传递bean后置处理器的方法 postProcessBeforeInitialization
        4. 调用bean的初始化方法(需要配置初始化方法)
        5. 把bean实例传递bean后置处理器的方法postProcessAfterInitialization
        6. bean可以使用了(bean对象获取到了)
        7. 当容器关闭的时候,调用bean的销毁方法(需要配置销毁的方法)
      • 配置后置处理器

        <bean id="orders" class="com.atguigu.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
        <property name="oname" value="手机"></property>
        </bean>
        
        <!--配置后置处理器-->
        <bean id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost"></bean>
        
        创建类,实现接口BeanPostProcessor,创建后置处理器
            public class MyBeanPost implements BeanPostProcessor {
                @Override
                public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
                    System.out.println("在初始化之前执行的方法");
                    return bean;
                }
                @Override
                public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                    System.out.println("在初始化之后执行的方法");
                    return bean;
                }
            }
        
            @Test
            public void testBean3() {
                ClassPathXmlApplicationContext context =
                        new ClassPathXmlApplicationContext("bean4.xml");
                Orders orders = context.getBean("orders", Orders.class);
                System.out.println("第四步 获取创建bean实例对象");
                System.out.println(orders);
        
                //手动让bean实例销毁
                context.close();
            }
        

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hgTlsn9V-1654580557504)(C:\Users\StarLee\AppData\Roaming\Typora\typora-user-images\image-20220519222543438.png)]

后置处理器在xml配置后加载后就生效了


  • iOC操作bean管理(xml自动装配)

    • 什么是自动装配

      • 根据指定装配规则(根据属性名称或者属性类型),Spring自动匹配属性进行注入

      • 演示自动装配

        public class Emp {
            private Dept dept;
            public void setDept(Dept dept) {
                this.dept = dept;
            }
        
            @Override
            public String toString() {
                return "Emp{" +
                        "dept=" + dept +
                        '}';
            }
        
            public void test() {
                System.out.println(dept);
            }
        }
        
        <!--实现自动装配
                bean标签属性autowire,配置自动装配
                autowire属性常用两个值:
                    byName根据属性名称注入 ,注入值bean的id值和类属性名称一样
                    byType根据属性类型注入
            -->
        <bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byType">
            <!--<property name="dept" ref="dept"></property>-->
        </bean>
        <bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
        

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pD6RvtnT-1654580557504)(C:\Users\StarLee\AppData\Roaming\Typora\typora-user-images\image-20220519223928317.png)]

    • ioc操作bean管理(引入外部配置文件)

      • 创建外部配置文件,properties 格式文件,写数据库信息

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xNtbx8kd-1654580557504)(C:\Users\StarLee\AppData\Roaming\Typora\typora-user-images\image-20220519224253308.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ASvWJDaL-1654580557505)(C:\Users\StarLee\AppData\Roaming\Typora\typora-user-images\image-20220519224413492.png)]
      在这里插入图片描述

      • 把外部 properties 属性文件引入到 spring 配置文件中
        引入 context 名称空间 context:property-placeholder
        placeholder 占位符

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0g3wjbMp-1654580557505)(C:\Users\StarLee\AppData\Roaming\Typora\typora-user-images\image-20220519224943348.png)]

  • IOC操作bean管理(注解方式)

    • 什么是注解

      • 注解是代码特殊标记,格式 :@注解名称(属性名称=属性值,属性名称=属性值…)
      • 使用注解 注解作用于类上面,属性上面,方法上面
      • 使用注解的目的:简化xml配置
    • Spring针对bean管理中创建对象提供的注解

      • @Component
      • @Controller
      • @Service
      • @Repository
    • 基于注解方式的对象创建

      • 引入依赖

      • 开启组件扫描

        <!--开启组件扫描
         1 如果扫描多个包,多个包使用逗号隔开
         2 扫描包上层目录
        -->
        <context:component-scan base-package="com.atguigu"></context:component-scan>
        
      • 创建类在类上面添加注解

        //在注解里面 value 属性值可以省略不写,
        //默认值是类名称,首字母小写
        //UserService -- userService
        @Component(value = "userService") //<bean id="userService" class=".."/>
        public class UserService {
            public void add() {
                System.out.println("service add.......");
            }
        }
        
        
    • 基于注解方式实现属性注入

      • @Autowired:根据属性类型进行自动装配

        //定义 dao 类型属性
        //不需要添加 set 方法
        //添加注入属性注解
        @Autowired 
        private UserDao userDao;
        
      • @Qualifier:根据名称进行注入
        这个@Qualifier 注解的使用,和上面@Autowired 一起使用

        //定义 dao 类型属性
        //不需要添加 set 方法
        //添加注入属性注解
        @Autowired //根据类型进行注入
        @Qualifier(value = "userDaoImpl1") //根据名称进行注入
        private UserDao userDao;
        
      • @Resource:可以根据类型注入,可以根据名称注入

        //@Resource //根据类型进行注入
        @Resource(name = "userDaoImpl1") //根据名称进行注入
        private UserDao userDao;
        
      • @Value:注入基本类型属性

        @Value(value = "abc")
        private String name;
        
    • 完全注解开发

      • 创建配置类替代xml配置文件

        @Configuration //作为配置类,替代 xml 配置文件
        @ComponentScan(basePackages = {"com.atguigu"}) //代替<context:component-scan >
        public class SpringConfig {
        }
        
      • 测试代码 AnnotationConfigApplicationContext

        package com.atguigu;
        
        @Service
        public class UserService {
        
            @Value(value = "abc")
            private String name;
        }
        
        @Test
        public void testService2() {
            //加载配置类
            ApplicationContext context
                = new AnnotationConfigApplicationContext(SpringConfig.class);
            UserService userService = context.getBean("userService", UserService.class);
            System.out.println(userService);
        }
        

AOP

什么是Aop
  • 面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护。
AOP底层原理
  • AOP底层是动态代理(jdk动态代理,cglib动态代理)

    • 有接口的情况,使用jdk动态代理

      • 创建接口的实现类代理对象,增强类的方法
    • 没有接口的情况,使用cglib动态代理

      • 创建该类的子类的代理对象,增强类的方法

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4immHo5j-1654580557505)(D:\BaiduNetdiskDownload\spring5\笔记\笔记\分析图\图4.png)]

  • AOP(JDK动态代理)

    • 使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EimNvXyG-1654580557506)(C:\Users\StarLee\AppData\Roaming\Typora\typora-user-images\image-20220519234725197.png)]

    • 调用newProxyInstance方法

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XeKODcTn-1654580557506)(C:\Users\StarLee\AppData\Roaming\Typora\typora-user-images\image-20220519234819159.png)]

      方法三个参数

      • 第一参数,类加载器
      • 第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
      • 第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分
    • 编写JDK动态代理代码

      • 创建接口定义方法

        public interface UserDao {
         public int add(int a,int b);
         public String update(String id);
        }
        
      • 创建接口实现类,实现方法

        public class UserDaoImpl implements UserDao {
            @Override
            public int add(int a, int b) {
                return a+b;
            }
            @Override
            public String update(String id) {
                return id;
            }
        }
        
      • 使用 Proxy 类创建接口代理对象

        public class JDKProxy {
        
            public static void main(String[] args) {
                //创建接口实现类代理对象
                Class[] interfaces = {UserDao.class};
        //        Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
        //            @Override
        //            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //                return null;
        //            }
        //        });
                UserDaoImpl userDao = new UserDaoImpl();
                UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
                int result = dao.add(1, 2);
                System.out.println("result:"+result);
            }
        }
        
        //创建代理对象代码
        class UserDaoProxy implements InvocationHandler {
        
            //1 把创建的是谁的代理对象,把谁传递过来
            //有参数构造传递
            private Object obj;
            public UserDaoProxy(Object obj) {
                this.obj = obj;
            }
        
            //增强的逻辑
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //方法之前
                System.out.println("方法之前执行...."+method.getName()+" :传递的参数..."+ Arrays.toString(args));
        
                //被增强的方法执行
                Object res = method.invoke(obj, args);
        
                //方法之后
                System.out.println("方法之后执行...."+obj);
                return res;
            }
        }
        
  • AOP(术语)

    • 连接点
      类里面的那些方法可以被增强,这些方法都叫做链接点
    • 切入点
      类中真正被增强的方法
    • 通知(增强)
      实际增强的逻辑称为通知
      • 前置通知
      • 后置通知
      • 环绕通知
      • 异常通知
      • 最终通知
    • 切面
      是动作,把通知织如切入点的过程(自己把增强的类称为切面)
  • AOP操作

    • Spring 框架一般都是基于 AspectJ 实现 AOP 操作,AspectJ 不是 Spring 组成部分,独立 AOP 框架

    • 基于 AspectJ 实现 AOP 操作

      • 基于 xml 配置文件实现
      • 基于注解方式实现使用
    • 切入点表达式

      • 切入点表达式作用:知道对哪个类里面的哪个方法进行增强
      • 语法结构: execution([权限修饰符] [返回类型] [类全路径] 【方法名称】([参数列表]) )
        • 访问权限修饰符可以为 * 表示所有
        • 返回类型可以为空
        • 方法名称可以为 * 表示所有
        • 参数列表可以 …
      • 举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
        execution(* com.atguigu.dao.BookDao.add(…))
      • 举例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
        execution(* com.atguigu.dao.BookDao.* (…))
      • 举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
        execution(* com.atguigu.dao.. (…))
    • 代码

      • 创建类,在类里面定义方法 cglib

        • public class User {
              public void add() {
                  System.out.println("add.......");
              }
          }
          
      • 创建增强类(编写增强逻辑)

        在增强类里面,创建方法,让不同方法代表不同通知类型

        • /增强的类
          public class UserProxy {
           public void before() {//前置通知
           System.out.println("before......");
           }
          }
          
      • 进行通知的配置

        1. 开启注解扫描(两种方式xml,或者注解)

        2. 使用注解创建 User 和 UserProxy 对象

        //被增强的类
        @Conponent
        public class User{
            
        //增强类
        @Conponent
        public class UserProxy{}
        
        1. 在增强类上添加注解@Aspect生成代理对象

          @Component
          @Aspect //生成代理对象
          public class UserProxy {
          
        2. 开启生成代理对象两种方式(xml,或者注解)

          • <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
            
          • @EnableAspectJAutoProxy

      • 配置不同类型通知

        • 在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

          @Component
          @Aspect //生成代理对象
          public class UserProxy {
              //前置通知
              //@Before 注解表示作为前置通知
              @Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
              public void before() {
                  System.out.println("before.........");
              }
              //后置通知(返回通知)
              @AfterReturning(value = "execution(* 
                              com.atguigu.spring5.aopanno.User.add(..))")
                  public void afterReturning() {
                  System.out.println("afterReturning.........");
              }
              //最终通知
              @After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
              public void after() {
                  System.out.println("after.........");
              }
              //异常通知
              @AfterThrowing(value = "execution(* 
                             com.atguigu.spring5.aopanno.User.add(..))")
                  public void afterThrowing() {
                  System.out.println("afterThrowing.........");
              }
              //环绕通知
              @Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
              public void around(ProceedingJoinPoint proceedingJoinPoint) throws 
                  Throwable {
                  System.out.println("环绕之前.........");
                  //被增强的方法执行
                  proceedingJoinPoint.proceed();
                  System.out.println("环绕之后.........");
              }
          }
          
        • 相同切入点抽取 @Pointcut注解作用在方法上

          @Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
          public void pointdemo() {
          }
          //前置通知
          //@Before 注解表示作为前置通知
          @Before(value = "pointdemo()")
          public void before() {
              System.out.println("before.........");
          }
          
        • 完全注解开发,不使用xml文件

          @Configuration
          @ComponentScan(basePackages = {"com.atguigu"})
          @EnableAspectJAutoProxy(proxyTargetClass = true)
          public class ConfigAop {
          }
          
        • xml 开发

          <!--创建对象-->
          <bean id="book" class="com.atguigu.spring5.aopxml.Book"></bean>
          <bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean>
          
          <!--配置 aop 增强-->
          <aop:config>
              <!--切入点-->
              <aop:pointcut id="p" expression="execution(* 
                                               com.atguigu.spring5.aopxml.Book.buy(..))"/>
              <!--配置切面-->
              <aop:aspect ref="bookProxy">
                  <!--增强作用在具体的方法上-->
                  <aop:before method="before" pointcut-ref="p"/>
              </aop:aspect>
          </aop:config>
          

          [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MLlLJuzH-1654580557506)(C:\Users\StarLee\AppData\Roaming\Typora\typora-user-images\image-20220520004240696.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值