Spring相关知识复习

Spring框架

Spring框架是一个集众多设计模式于一身的开源的、轻量级的项目管理框架。致力于JAVAEE轻量级解决方案。

轻量级解决方案:提供一个以简单的、统一的、搞笑的方式构造整个应用,并且可以将单层框架以最佳的组合糅合在一起建立一个连贯的体系

 Spring框架的核心作用

Spring框架用来管理[创建|使用|销毁]项目中的组件,由于Spring框架可以帮我们生产项目中组件对象,因此也习惯称Spring是一个工厂|容器

组件:项目中的service,dao,controller都是项目中的组件

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

    <!--管理组件对象的创建-->
    <!--bean标签负责组件对象的管理  一个bean标签只负责一个组件对象
        class:要管理的组件    java类的全限定名  包名.类名
        id:组件对象在工厂中的唯一标识  建议命名 存在接口,接口首字母小写  类名首字母小写
    -->
    <bean id="userDao" class="init.UserDaoImpl"></bean>

</beans>

启动工厂测试

 public static void main(String[] args) {
		//启动工厂
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
		//获取对象
        UserDAO userDAO = (UserDAO) context.getBean("userDAO");

        userDAO.save("小黑");
    }

Spring框架中的核心思想

IOC[控制反转]

IOC (inversion of controll)        控制反转

将对象的创建由原来的方式转移到配置文件中,交给Spring工厂来创建对象

DI  (dependcy Injection)           依赖注入

Spring不仅要创建对象,还要建立类与类之间的关系,因此在控制反转的基础啊上又提出了依赖注入的概念

Set方式注入

<!--八种基本数据类型+String类型+日期类型的注入-->
<property name="name" value="xxxx"/>
<property name="age" value="18"/>
<property name="id" value="1001"/>
<property name="birthday" value="2021/12/27"/>
<property nem="price" value="19.99"/>
<!--注入数组类型的数据-->
<property name="names">
    <array>
        <value>xxx</value>
        <value>qiqi</value>
        <value>jinjin</value>
    </array>
</property>
<!--注入引用类型和对象-->
<property name="userDao" ref="userDao"/>
<property name="lists">
    <list>
        <value>aaa</value>
        <value>bbb</value>
        <value>ccc</value>
    </list>
</property>

<property name="maps">
    <map>
        <entry key="aa" value="小白"/>
        <entry key="bb" value="小黑"/>
        <entry key="cc" value="小芬"/>
    </map>
</property>

<property name="props">
    <props>
        <prop key="url">jdbc:mysql://localhost:3306</prop>
        <prop key="driver">com.mysql.jdbc.Driver</prop>
        <prop key="username">root</prop>
        <prop key="password">root</prop>
    </props>
</property>

注意:引用类型使用ref属性注入,基本类型使用value属性注入

构造注入

<constructor-arg index="0" name="id" value="1"/>
<constructor-arg index="1" name="name" value="xxx"/>
<constructor-arg index="2" name="age" value="18"/>
<constructor-arg index="3" name="tels">
    <array>
        <value>111223456</value>
        <value>223456445</value>
        <value>333456445</value>
    </array>
</constructor-arg>

自动注入

autowire="byName"
根据注入的属性名与配置文件中的bean的id匹配,一致则注入,不一致报错

autowire="byType"
根据注入的属性类型,与配置文件中的类型匹配,类型一致注入(在多个实现类时,会产生歧义)

无论使用以上哪种方式注入都需要为属性提供set方法

bean的创建模式

singleton:单例        默认

在工厂中全局唯一,只创建一次

prototype:多例

全局不唯一,每次使用都会创建一个新的对象

<bean id=" " class="xxxx.userCotroller" scope="prototype  |  singleton">

                service   dao   -------------->  singleton
                controller        --------------->   propotype

bean的生产原理

原理:反射+构造方法

userDaoImpl userDao =(UserDaoImpl)Class.forName("com.tjcu.dao.UserDaoImpl").newInstance();
System.out.println(userDao);

bean的生命周期

何时创建

        随着工厂启动,所有单例bean随之创建  非单例的bean,每次使用时创建

何时销毁

        工厂关闭,所有bean随之销毁(注意:Spring不会负责多例bean的销毁)

bean工厂创建对象的好处

1、使用配置文件管理Java类,在生产环境中更换类的实现时不需要重新部署,修改文件即可

2、Spring默认使用单例的模式创建bean,减少内存的占用

3、通过依赖注入建立了类与类之间的关系(使Java之间关系更为清晰,方便了维护与管理)

代理

什么是代理?
        代理指的是Java中的一种设计模式

为什么需要代理?
        很多时候除了当前类能够提供的功能外,我们还需要补充一些额外功能

代理的作用?
        代理对象可以在客户和目标对象之间起到中介作用,从而外目标对象增添额外的功能

静态代理的开发

目标类|对象(target):被代理类称之为目标类|或者被代理的对象称之为目标对象

目标对象

        开发代理的原则:代理类和目标类的功能一致且实现相同的接口,同时代理类中依赖于目标类对象

开发静态代理类

//静态代理类
//开发原则:代理类和目标类实现相同接口,依赖于真正的目标类
public class UserServiceStaticProxy implements UserService {

    //真正的目标类 //target 原始业务逻辑对象
    private UserService userService;
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @Override
    public void save(String name) {
        try {
            System.out.println("开启事务");
            userService.save(name);//调用真正业务逻辑方法
            System.out.println("提交事务");
        }catch (Exception e){
            System.out.println("回滚事务");
            e.printStackTrace();
        }
    }

    @Override
    public void delete(String id) {
        try {
            System.out.println("开启事务");
            userService.delete(id);//调用真正业务逻辑方法
            System.out.println("提交事务");
        }catch (Exception e){
            System.out.println("回滚事务");
            e.printStackTrace();
        }
    }

    @Override
    public void update() {
        try {
            System.out.println("开启事务");
            userService.update();//调用真正业务逻辑方法
            System.out.println("提交事务");
        }catch (Exception e){
            System.out.println("回滚事务");
            e.printStackTrace();
        }
    }

    @Override
    public String findAll(String name) {
        try {
            System.out.println("开启事务");
            String result = userService.findAll(name);//调用真正业务逻辑方法
            System.out.println("提交事务");
            return result;
        }catch (Exception e){
            System.out.println("回滚事务");
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String findOne(String id) {
        try {
            System.out.println("开启事务");
            //调用目标类方法
            String one = userService.findOne(id);//调用真正业务逻辑方法
            System.out.println("提交事务");
            return one;
        }catch (Exception e){
            System.out.println("回滚事务");
            e.printStackTrace();
        }
        return null;
    }
}

更改目标实现类

public class UserServiceImpl implements UserService {
    @Override
    public void save(String name) {
        System.out.println("处理业务逻辑,调用DAO~~~");
    }

    @Override
    public void delete(String id) {
        System.out.println("处理业务逻辑,调用DAO~~~");
    }

    @Override
    public void update() {
        System.out.println("处理业务逻辑,调用DAO~~~");
    }

    @Override
    public String findAll(String name) {
        System.out.println("处理业务逻辑,调用DAO~~~");
        return name;
    }

    @Override
    public String findOne(String id) {
        System.out.println("处理业务逻辑,调用Dao~~~");
        return id;
    }
}

配置静态代理类

		<!--配置目标类-->
    <bean id="userService" class="staticproxy.UserServiceImpl"></bean>

    <!--配置代理类-->
    <bean id="userServiceStaticProxy" class="staticproxy.UserServiceStaticProxy">
        <!--注入目标对象-->
        <property name="userService" ref="userService"/>
    </bean>

调用代理方法

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userServiceStaticProxy = (UserService) context.getBean("userServiceStaticProxy");
userServiceStaticProxy.save("小黑");

问题:在开发中我们书写的不仅仅是一个业务层,我们的业务层会有很多,如果为每一个业务类开发一个静态代理类,造成业务代码冗余的问题

为业务层在运行过程中动态创建代理类,通过代理类解决业务层中业务代码冗余的问题

动态代理的原理

public class TestDynamicProxy {
    public static void main(String[] args) {
        final UserService userService =  new UserServiceImpl();
        //参数1:当前线程类加载器
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        //参数2:生成代理类的接口类型
        Class[] classes =  new Class[]{UserService.class};
        //参数3:通过代理类对象调用方法时会有限进入参数三中的invoke方法
        //返回值就是动态代理对象
        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(contextClassLoader, classes, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                try{
                    System.out.println("开启事务");//附加操作
                    Object invoke = method.invoke(userService, args);
                    System.out.println("提交事务");//附加操作
                    return invoke;
                }catch (Exception e){
                    System.out.println("回滚事务");//附加操作
                }
                return null;
            }
        });
        userServiceProxy.save("小黑");
    }
}

AOP[面向切面编程]

AOP(Aspect Oriental Programing)面向切面的编程

通知(Advice):除了目标方法以外的操作都称之为通知

切入点(PointCut):要为哪些类中的哪些方法加入通知

切面(Aspect):通知+切入点

通知分类

步骤

    <!--1.引入依赖  pom.xml
        2.开发通知类 选择哪一种通知
    MethodBeforeAdvice      前置通知
    MethodInterceptor       环绕通知
    AfterReturningAdvice    返回后通知
    ThrowsAdvice			  异常通知

    MyAdvice implements  通知接口{.....}
        
        自定义通知类:用来完成额外功能
    public class MyAdvice  implements MethodBeforeAdvice {
        @Override    //参数1:当前调用的方法对象    //参数2:当前调用方法对象的参数  //参数3:目标对象
        public void before(Method method, Object[] objects, Object o) throws Throwable {
            System.out.println("目标方法名: "+method.getName());
            System.out.println("目标方法的参数: "+objects);
            System.out.println("目标对象: "+o.getClass());
        }
    }
        3.组装切面
    a.引入aop命名空间

        b.管理通知-->
        <!--管理通知类-->
        <bean id="myAdvice" class="before.MyAdvice"/>
        c.配置切面
        <aop:config>
            <!--配置切入点 id:切入点唯一标识 expression:切入点表达式 确认要为哪些类添加额外功能
            execution()切入点表达式的一种 精确到要添加额外功能的方法
            
            -->
            <aop:pointcut id="pc" expression="execution(* before.UserServiceImpl.*(..))"/>
            <--advice-ref:已有通知的id  pointcut-ref:已有切入点的id-->
            <aop:advisor advice-ref="myAdvice" pointcut-ref="pc"/>
        </aop:config>

    <!--4.启动工厂测试-->
        //启动工厂
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("before/spring.xml");
        //获取组件
        UserService userSerivce = (UserService) context.getBean("userService");
        System.out.println(userSerivce.getClass());
        //调用方法 通过代理类调用方法
        userSerivce.save("小黑");

通知[接口]

1.前置通知(MethodBeforeAdvice)的使用

 2.环绕通知(MethodInterceptor)的使用

 3.返回后(后置)(AfterReturningAdvice)通知

 4.异常(ThrowAdvice)通知

目标方法正常执行结束,执行后置通知

如果目标方法执行出现异常,才执行异常通知

切入点表达式

作用:通知Spring框架要为哪些类生成动态代理对象

1.execution方法级别的切入点表达式

execution[访问修饰符]返回值 包名.类名.方法名(参数表)        [  ]中的内容可以省略

注意:书写访问修饰符 返回值 包名 类名 方法名时 都支持通配    *表示任意

书写参数表时支持通配 ..表示任意

execution常用方式:

 注意:方法级别的切入点表达式尽可能精准,否则程序可能出现异常

2、within类级别的切入点表达式        精确到类

1.语法
    within(包.类)

    书写包名 类名时 也支持通配 *表示任意
2.示例
    within(com.baizhi.service.*) 
            包: com.baizhi.service
            类: 所有类中所有方法不关心返回值和参数
    
    within(com.baizhi.service.UserServiceImpl)
            包: com.baizhi.service
            类: UserServiceImpl类中所有方法不关心返回值和参数

3、注意[自定义注解]

注意:within的效率高于execution表达式,推荐使用within表达式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值