SSM【Spring SpringMVC Mybatis】—— Spring(二)

如果对于Spring的一些基础理论感兴趣可见👇

SSM【Spring SpringMVC Mybatis】—— Spring(一)

目录

1、Spring中bean的作用域

1.1 语法

1.2 四个作用域

2、Spring中bean的生命周期

2.1 bean的生命周期

2.2 bean的后置处理器

2.3 添加后置处理器后bean的生命周期

3、Spring中自动装配【基于XML】

3.1 Spring中提供两种装配方式

3.2 Spring自动装配语法及规则

3.3 总结

4、Spring中注解【非常重要】

4.1 使用注解将对象装配到IOC容器中

4.2 使用注解装配对象中属性【自动装配】

自动装配(Autowired):

限定装配(Qualifier):

字面量数值装配(Value):

5、Spring完全注解开发【0配置】

5.1 完全注解开发步骤

5.2 示例代码

6、AOP前奏

6.1 代理模式

6.2 为什么需要代理【程序中】

6.3 手动实现动态代理环境搭建

6.4 手动实现动态代理关键步骤


1、Spring中bean的作用域

1.1 语法

在bean标签中添加属性:scope属性即可

<bean id="myBean" class="com.example.MyBean" scope="singleton"/>

1.2 四个作用域

  • singleton(默认值):单例模式,容器中只存在一个bean实例。

    • 对象创建时机:当创建Spring容器时,bean实例会被创建并放入容器中。
  • prototype:原型模式,每次获取bean时都会创建一个新的实例。

    • 对象创建时机:当调用getBean()方法获取bean实例时,每次都会创建一个新的实例。
  • request:请求作用域,每个HTTP请求都会创建一个新的bean实例。

    • 对象创建时机:每次HTTP请求到达时,都会创建一个新的bean实例,并在当前请求结束后销毁。
    • 当前请求:即URL不变的情况下,同一个HTTP请求中的所有处理都处于同一个请求域中。
  • session:会话作用域,每个HTTP会话都会创建一个新的bean实例。

    • 对象创建时机:在用户会话开始时创建一个bean实例,并在用户会话结束后销毁。
    • 当前会话:即用户在浏览器上不关闭、不更换的情况下持续访问应用的时间段。

2、Spring中bean的生命周期

2.1 bean的生命周期

  1. 通过构造器或工厂方法创建bean实例:Spring容器根据配置信息和依赖关系,使用构造器或工厂方法创建bean实例。

  2. 为bean的属性设置值和对其他bean的引用:Spring容器注入bean的属性值和依赖的其他bean。

  3. 调用bean的初始化方法:如果bean配置了初始化方法,Spring容器会在属性注入完成后调用该方法进行初始化。

  4. bean可以使用了:bean初始化完成后,可以被其他bean或应用程序代码引用和使用。

  5. 当容器关闭时,调用bean的销毁方法:如果bean配置了销毁方法,当Spring容器关闭时,会调用该方法进行清理工作。

2.2 bean的后置处理器

作用:在调用初始化方法前后对bean进行额外的处理。

实现:

实现BeanPostProcessor接口

重写方法

postProcessBeforeInitialization(Object, String):在bean的初始化方法调用之前调用,允许修改bean的属性值或做其他处理。

postProcessAfterInitialization(Object, String):在bean的初始化方法调用之后调用,允许在bean初始化完成后进行额外的处理。

注意:装配后置处理器会为当前容器中每个bean均装配,不能为局部bean装配后置处理器

2.3 添加后置处理器后bean的生命周期

① 通过构造器或工厂方法创建bean实例

② 为bean的属性设置值和对其他bean的引用

postProcessBeforeInitialization(Object, String):在bean的初始化之前执行

③ 调用bean的初始化方法

postProcessAfterInitialization(Object, String):在bean的初始化之后执行

④  bean可以使用了

⑤ 当容器关闭时,调用bean的销毁方法

3、Spring中自动装配【基于XML】

3.1 Spring中提供两种装配方式

手动装配:通过XML文件或Java配置显式地指定bean之间的依赖关系。

自动装配:让Spring容器根据一定的规则自动将合适的bean注入到目标bean中,而不需要显式地在配置文件中声明这些依赖关系。

3.2 Spring自动装配语法及规则

在bean标签中添加属性:Autowire即可,

常用的有两种:

  • byName:根据属性名称自动装配。Spring会查找与属性名相同的bean,并将其注入到目标bean的属性中。

  • byType:根据属性类型自动装配。Spring会查找与属性类型相同的bean,并将其注入到目标bean的属性中。如果找到多个匹配的bean,则会报错。

注意:基于XML方式的自动装配只能装配非字面量数值(即不是直接指定的常量值)。

3.3 总结

在基于XML的自动装配中,底层实际上是通过setter方法进行注入的。但通常不推荐使用byName和byType方式进行自动装配,因为它们可能会导致不可预期的结果,特别是在大型项目中容易出现问题。相反,建议使用注解方式进行自动装配。

4、Spring中注解【非常重要】

4.1 使用注解将对象装配到IOC容器中

约定:约束>配置【注解>XML】>代码

位置:在类上面标识

注意:

Spring本身不区分四个注解【四个注解本质是一样的@Component】,提供四个注解的目的只有一个:提高代码的可读性

在使用注解装配对象时,Spring会默认将类名的首字母小写作为bean的ID。你也可以使用value属性来指定bean的ID。

装配对象四个注解

@Component:装配普通组件到IOC容器

@Repository:装配持久化层组件到IOC容器

@Service:装配业务逻辑层组件到IOC容器

@Controller:装配控制层|表示层组件到IOC容器

使用注解步骤

导入相关jar包【已导入】

开启组件扫描

    <!--    开启组件扫描

            base-package:设置扫描注解包名【当前包及其子包】

    -->

    <context:component-scan base-package="com.atguigu"></context:component-scan>

使用注解标识组件

4.2 使用注解装配对象中属性【自动装配】

自动装配(Autowired):
  • 使用@Autowired注解可以实现对象属性的自动装配。
  • 装配原理基于反射机制,Spring会尝试按照byType进行匹配。
  • 如果匹配到一个对象,则正常使用。
  • 如果匹配不到对象,默认情况下会报错,但可以通过设置@Autowired(required=false)来避免报错。
  • 如果匹配到多个对象,会尝试按照byName进行唯一筛选,如果筛选失败则报错。
  • @Autowired注解的required属性可以设置为true或false,表示是否必须装配对象。

          /*expected at least 1 bean which qualifies as autowire candidate.   Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

          */
限定装配(Qualifier):

@Qualifier注解

作用:配合@Autowired一起使用,将设置beanId名称装配到属性中

注意:不能单独使用,需要与@Autowired一起使用

字面量数值装配(Value):

@Value注解

作用:装配对象中属性【字面量数值】

5、Spring完全注解开发【0配置】

5.1 完全注解开发步骤

5.1.1. 创建配置类

5.1.2. 在class上面添加注解

@Configuration:标识当前类是一个配置类,作用:代替XML配置文件

@ComponentScan:设置组件扫描当前包及其子包

5.1.3. 使用AnnotationConfigApplicationContext容器对象

5.2 示例代码

@Configuration

@ComponentScan(basePackages = "com.atguigu")

public class SpringConfig {

}

  @Test

    public void test0Xml(){

        //创建容器对象

//        ApplicationContext context =

//                new ClassPathXmlApplicationContext("applicationContext.xml");

        //使用AnnotationConfigApplicationContext容器对象

        ApplicationContext context =

                new AnnotationConfigApplicationContext(SpringConfig.class);

        DeptDaoImpl deptDao = context.getBean("deptDao", DeptDaoImpl.class);



        System.out.println("deptDao = " + deptDao);

    }

6、AOP前奏

6.1 代理模式

代理模式:我们需要做一件事情,又不期望自己亲力亲为,此时,可以找一个代理【中介】

我们【目标对象】与中介【代理对象】不能相互转换,因为是“兄弟”关系

  

6.2 为什么需要代理【程序中】

需求:实现【加减乘除】计算器类

在加减乘除方法中,添加日志功能【在计算之前,记录日志。在计算之后,显示结果。】

实现后发现问题如下

日志代码比较分散,可以提取日志类

日志代码比较混乱,日志代码【非核心业务代码】与加减乘除方法【核心业务代码】书写一处

总结:在核心业务代码中,需要添加日志功能,但不期望在核心业务代码中书写日志代码。

此时:使用代理模式解决问题【先将日志代码横向提取到日志类中,再动态织入回到业务代码中】

6.3 手动实现动态代理环境搭建

实现方式

基于接口实现动态代理: JDK动态代理

基于继承实现动态代理: Cglib、Javassist动态代理

实现动态代理关键步骤

 一个类:Proxy

概述:Proxy代理类的基类【类似Object】

作用:newProxyInstance():创建代理对象

一个接口:InvocationHandler

概述:实现【动态织入效果】关键接口

作用:invoke(),执行invoke()实现动态织入效果

6.4 手动实现动态代理关键步骤

注意:代理对象与实现类【目标对象】是“兄弟”关系,不能相互转换

创建类【为了实现创建代理对象工具类】

提供属性【目标对象:实现类】

提供方法【创建代理对象】

提供有参构造器【避免目标对为空】


package com.atguigu.beforeaop;



import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;





public class MyProxy {



    /**

     * 目标对象【目标客户】

     */

    private Object target;



    public MyProxy(Object target){

        this.target = target;

    }



    /**

     * 获取目标对象的,代理对象

     * @return

     */

    public Object getProxyObject(){

        Object proxyObj = null;



        /**

            类加载器【ClassLoader loader】,目标对象类加载器

            目标对象实现接口:Class<?>[] interfaces,目标对象实现所有接口

            InvocationHandler h

         */

        ClassLoader classLoader = target.getClass().getClassLoader();

        Class<?>[] interfaces = target.getClass().getInterfaces();

        //创建代理对象

        proxyObj = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {

            //执行invoke()实现动态织入效果

            @Override

            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                //获取方法名【目标对象】

                String methodName = method.getName();

                //执行目标方法之前,添加日志

                MyLogging.beforeMethod(methodName,args);

                //触发目标对象目标方法

                Object rs = method.invoke(target, args);

                //执行目标方法之后,添加日志

                MyLogging.afterMethod(methodName,rs);

                return rs;

            }

        });

        return proxyObj;

    }



//    class invocationImpl implements InvocationHandler{

//    }



}




@Test

    public void testBeforeAop(){



//        int add = calc.add(1, 2);

//        System.out.println("add = " + add);



        //目标对象

        Calc calc = new CalcImpl();

        //代理工具类

        MyProxy myProxy = new MyProxy(calc);

        //获取代理对象

        Calc calcProxy = (Calc)myProxy.getProxyObject();

        //测试

//        int add = calcProxy.add(1, 2);

        int div = calcProxy.div(2, 1);



    }













 

  • 44
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值