Spring框架

一.SpringIOC

  • IOC:控制反转,把对象的创建和对象之间的调用过程交给Spring进行管理
  • 使用IOC的目的:代码的耦合度降低了

二. IOC之BeanFactory

  • IOC思想是基于IOC容器完成的,IOC容器就是对象工厂
  • Spring提供IOC容器两种实现方式:
    • BeanFactory提供了IOC的基本实现,是Spring内部接口,不提供给开发人员使用,加载配置文件的时候不会创建对象,当我们获取对象的时候才会创建对象
    • ApplicationContext :是BeanFactory的子接口,提供了更为强大的功能,一般由开发人员来使用,加载配置文件就会创建对象

三.IOC操作的Bean

1.创建对象

  • id为对象名
  • class为类的全限定名
<bean id="user" class="com.sunyanshu.pojo.User"></bean>

2.属性注入

2.1set注入

  • 必须要有set方法,否则会报错
  • name为属性名,value为属性值

方式一

<bean id="book1" class="com.sunyanshu.pojo.Book">
        <property name="name" value="小时代"></property>
        <property name="price" value="37"></property>
    </bean>

方式二

<bean id="emp2" class="com.sunyanshu.entity.Emp">
        <property name="name" value="斯卡拉姆齐"></property>
        <property name="sex" value="男"></property>
        
        <property name="dept">
            <bean id="dept2" class="com.sunyanshu.entity.Dept">
                <property name="name" value="愚人众执行官"></property>
            </bean>
        </property>
        
    </bean>

2.2构造注入

  • 必须要有有参构造
<bean id="book3" class="com.sunyanshu.pojo.Book">
        <constructor-arg name="name" value="朝花夕拾"></constructor-arg>
        <constructor-arg name="price" value="276.2"></constructor-arg>
    </bean>

2.3p命名注入

<bean id="book4" class="com.sunyanshu.pojo.Book" p:name="溺光之翼" p:price="234.5"></bean>

2.4对象注入(使用ref引用)

方式一:接口与实现类

<bean id="teacherDaoImpl" class="com.sunyanshu.dao.impl.TeacherDaoImpl"></bean>
    <bean id="teacherService" class="com.sunyanshu.service.TeacherService">
        <property name="teacherDao" ref="teacherDaoImpl"></property>
    </bean>

方式二:类中使用另外的类作为属性

<bean id="dept1" class="com.sunyanshu.entity.Dept">
        <property name="name" value="壁炉之家"></property>
    </bean>
    <bean id="emp1" class="com.sunyanshu.entity.Emp">
        <property name="name" value="林尼"></property>
        <property name="sex" value="男"></property>
        <property name="dept" ref="dept1"></property>
    </bean>

2.5特殊数据注入(如set、map、list、数组)

<bean id="myEntity" class="com.sunyanshu.domain.MyEntity">
        <!--数组-->
        <property name="genshin">
            <array>
                <value>公子</value>
                <value>夜兰</value>
                <value>斯卡拉姆齐</value>
                <value>博士</value>
            </array>
        </property>

        <!--set集合-->
        <property name="set">
            <set>
                <value>蒙德</value>
                <value>枫丹</value>
                <value>至冬</value>
                <value>纳塔</value>
            </set>
        </property>

        <!--list集合-->
        <property name="list">
            <list>
                <value>三笠</value>
                <value>利威尔</value>
                <value>艾伦</value>
            </list>
        </property>

        <!--map集合-->
        <property name="map">
            <map>
                <entry key="java" value="高薪就业"></entry>
                <entry key="嵌入式" value="就业"></entry>
            </map>
        </property>
    </bean>

2.6自动装配

  • bean标签中的属性
    • autowire=“byName”: 名称注入,注入bean的id值和类中的属性名要一致

xml配置文件中

<bean id="emp" class="com.sunyanshu.entity.Emp" autowire="byName">
            <property name="name" value="张无忌"></property>
            <property name="sex" value="男"></property>
        </bean>
        <bean id="dept" class="com.sunyanshu.entity.Dept">
            <property name="name" value="明教"></property>
        </bean>
  • autowire=“byType”: 类型注入

xml配置文件中

<bean id="emp1" class="com.sunyanshu.entity.Emp" autowire="byType">
        <property name="name" value="利威尔"></property>
        <property name="sex" value="男"></property>
    </bean>
    <bean id="dept" class="com.sunyanshu.entity.Dept">
        <property name="name" value="调查兵团"></property>
    </bean>

3.获取对象

  • 步骤
    • 解析spring配置文件
    • 调用getBean()方法获取对象,其中第一个参数为对象名,需要和bean中的id一致;第二个参数为类的class对象
        //解析spring配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext1.xml");
        //获取对象
        User user = ac.getBean("user", User.class);

4.Bean的作用域

  • spring容器创建对象默认是单例模式(scope=“singleton”),可以手动修改为多例模式(scope=“prototype”)
  • 单例和多例的区别:单例在加载配置文件时创建对象,多例在getBean时创建对象

5.生命周期

  • bean的生命周期分两种情况
    • 第一种情况

      • 第一步:执行无参的构造方法
        • 在xml文件中创建bean对象时就会执行无参构造方法
      • 第二步:set方法设置属性值
        • 给属性设置值时才会执行这个方法,否则不执行
        • 在xml文件中给属性设置值,则在初始化之前执行;在获取对象后给属性设置值,则在初始化之后执行
      • 第三步:初始化方法
        • 在xml文件中的bean标签添加属性init-method才会执行这个方法
      • 第四步:获取创建好的bean对象
      • 第五步:销毁对象
        • 在xml文件中的bean标签添加属性destroy-method才会执行这个方法
        • 销毁对象:方式一
        • ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext2.xml"); ac.close();
        • 销毁对象:方式二
        • ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext2.xml");((ClassPathXmlApplicationContext) ac).close()
    • 第二种情况:配置bean的后置处理器(BeanPostProcessor)

      • 第一步:执行无参的构造方法
      • 第二步:set方法设置属性值
      • 在初始化之前执行的方法
      • 第三步:初始化方法
      • 在初始化之后执行的方法
      • 第四步:获取创建好的bean对象
      • 第五步:销毁对象
public class MyBean 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;
    }
}

xml文件中

<bean id="idol1" class="com.sunyanshu.pojo.Idol" init-method="initMethod" destroy-method="destroyMethod">
            <property name="name" value="三笠"></property>
        </bean>
        <bean id="myBean" class="com.sunyanshu.pojo.MyBean"></bean>

四.IOC基于注解方式开发

  • 创建bean实例的注解
    • @Component
    • @Service
    • @Controller
    • @Repository

这四个注解功能是一样的,都是用来创建bean实例的,想要创建bean实例需要在xml配置文件中开启扫描,如下

<!--开启扫描-->
    <context:component-scan base-package="org.sunyanshu"></context:component-scan>
  • 给成员变量赋值的注解(不需要写getset)
    • @Autowired:根据类型进行注入,自动装配
    • @Resource(name = “teacherDaoImpl”):根据名字进行注入,自动装配

五.AOP

面向切面编程(面向方面编程),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑之间的耦合度降低了,提高程序的性能

1.AOP术语

  • 连接点
    • 类里面的哪些方法可以被增强,这些方法成为连接点
  • 切入点
    • 实际上真正被增强的方法,称为切入点
  • 通知(增强)
    • 实际增强的逻辑部分称为通知[增强]
    • 通知的类型 :
      • 前置通知
      • 后置通知:若方法抛出异常,则后置通知不会执行
      • 环绕通知
      • 异常通知:在目标方法抛出异常时执行的通知
      • 最终通知:最终通知无论如何都会在目标方法调用过后执行,即使目标方法没有正常的执行完成
  • 切面
    • 把通知应用到切入点的过程

2.切入点表达式

  • 作用:知道哪个类中的哪个方法被增强
  • 格式:execution([权限修饰符][返回值类型][类全路径][方法名][参数列表])
    • 对cn.liushao.dao.BookDao类里面的add方法进行增强
      execution(* cn.liushao.dao.BookDao.add (. .))
    • 对cn.liushao.dao.BookDao类里面的所有方法进行增强
      execution(* cn.liushao.dao.BookDao.* (. .))
    • 对cn.liushao.dao包里面的所有类中所有方法进行增强
      execution(* cn.liushao.dao. * .* (. .))

3.面向切面编程

  • 第一版:使用bean,在spring配置文件中配置如下
<!--被增强类-->
    <bean id="user" class="edu.sunyanshu.entity.User"></bean>
    <!--增强类-->
    <bean id="userProxy" class="edu.sunyanshu.entity.UserProxy"></bean>
    <!--配置aop增强-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="p" expression="execution(* edu.sunyanshu.entity.User.genshin(..))"/>
        <!--配置切面-->
        <aop:aspect ref="userProxy">
            <!--前置通知-->
            <aop:before method="before" pointcut-ref="p"></aop:before>
            <!--后置通知-->
            <aop:after-returning method="afterReturning" pointcut-ref="p"></aop:after-returning>
            <!--最终通知-->
            <aop:after method="after" pointcut-ref="p"></aop:after>
            <!--异常通知-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="p"></aop:after-throwing>
            <!--环绕通知-->
            <aop:around method="around" pointcut-ref="p"></aop:around>
        </aop:aspect>
    </aop:config>

第二版:使用注解,在增强类中需要使用注解@Aspect生成代理对象

xml配置文件中

    <!--开启aspect生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

增强类中

@Component
@Aspect //生成代理对象
public class IdolProxy {
    //由于切入点表达式相同造成冗余,所以可以抽取出来
    @Pointcut(value = "execution(* edu.sunyanshu.domain.Idol.yj(..))")
    public void pointcut() {

    }

    @Before(value = "pointcut()")
    public void before() {
        System.out.println("前置通知--before");
    }

    @AfterReturning(value = "execution(* edu.sunyanshu.domain.Idol.yj(..))")
    public void afterReturning() {
        System.out.println("后置通知--afterReturning");
    }

    @After(value = "execution(* edu.sunyanshu.domain.Idol.yj(..))")
    public void after() {
        System.out.println("最终通知--after");
    }

    //在目标方法抛出异常时执行的通知
    @AfterThrowing(value = "pointcut()")
    public void afterThrowing() {
        System.out.println("异常通知--afterThrowing");
    }

    @Around(value = "pointcut()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知--around");
        System.out.println("环绕之前");
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后");
    }
}

六.Spring事务管理

  • 事务:事务是数据库操作的基本单元,逻辑上是一组操作,要么都成功,要么都失败,如果一个失败了,全部都失败
  • 使用场景:银行转账、下订单…
  • 事务的传播行为(propagation)
    • REQUIRED:如果有事务在运行,当前方法就在这个事务内运行,否则,就会启动一个新的事务,并在自己的事务内运行
    • REQUIRES_NEW:当前的方法必须启动新的事务,并在自己的事务内运行,如果有事务在运行,会将它挂起
    • SUPPORTS:如果有事务在运行,当前方法就在这个事务内运行,否则它可以不在事务内运行
    • NOT_SUPPORTED:当前的方法不应该运行在事务中,如果有运行的事务,将它挂起
    • MANDATORY:当前的方法必须运行在事务内部,如果没有运行的事务,就会抛出异常
    • NEVER:当前方法不应该运行在事务中,如果有运行的事务,就会抛出异常
    • NESTED:如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行
  • 事务的隔离级别(isolation)
    在这里插入图片描述
  • 事务注解(Transactional)中的五个属性
    • propagation:事务的传播行为
    • isolation:事务的隔离级别
    • timeout:以秒为单位
    • readOnly:默认值是false,如果设置为true,则只能查询
    • rollbackFor:回滚,后面指定异常类型,出现异常时则回滚

1.使用注解开发

事务注解(Transactional)可写在类上面,表示类中所有方法都开启事务,但一般不会这么写,因为查询不需要在事务环境下完成,事务要写在业务逻辑中
xml配置文件中

<!--配置数据源-->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///yeonjun"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <!--配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>

    <!--开启扫描-->
    <context:component-scan base-package="icu.sunyanshu"></context:component-scan>

    <!--配置事务管理器-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>

    <!--开启注解事务-->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

接口实现类中

@Repository
public class BankDaoImpl implements BankDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 增加钱
     */
    @Override
    public void addMoney() {
        //sql语句
        String sql = "update bank set money=money+? where id=?";
        //调用方法
        jdbcTemplate.update(sql, 100, 1);
    }

    /**
     * 减少钱
     */
    @Override
    public void reduceMoney() {
        //sql语句
        String sql = "update bank set money=money-? where id=?";
        //调用方法
        jdbcTemplate.update(sql, 100, 2);
    }
}

业务逻辑中

@Service
public class BankService {
    @Autowired
    private BankDao bankDao;

    /**
     * propagation:事务的传播行为
     * isolation:事务的隔离级别
     * timeout:以秒为单位
     * readOnly:默认值是false,如果设置为true,则只能查询
     * rollbackFor:回滚,后面指定异常类型
     */
    @Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.REPEATABLE_READ,
            timeout = 1000,
            readOnly = false,
            rollbackFor = Exception.class
    )
    public void accountMoney() {
        bankDao.reduceMoney();
        System.out.println("-------------");
        int i = 2 / 0;
        bankDao.addMoney();
        System.out.println("转账成功");
    }
}

2.使用xml开发

由于不使用注解,所以在业务逻辑和接口实现类中需要编写getset方法

xml配置文件中

<!--配置数据源-->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///yeonjun"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <!--配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>

    <!--创建对象-->
    <bean id="bankServiceNo" class="icu.sunyanshu.service.BankServiceNo">
        <property name="bankDaoNo" ref="bankDaoNoImpl"></property>
    </bean>
    <bean id="bankDaoNoImpl" class="icu.sunyanshu.dao.impl.BankDaoNoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>

    <!--配置通知-->
    <tx:advice id="txadvice">
        <!--配置事务参数-->
        <tx:attributes>
            <tx:method name="account" propagation="REQUIRED"/>
            <!--假设所有的添加方法都是以save开头并且所有添加方法都需要配置事务参数,那么配置编写如下-->
            <!--<tx:method name="save*" propagation="REQUIRED"/>-->
            <!--假设所有的删除方法都是以del开头并且所有删除方法都需要配置事务参数,那么配置编写如下-->
            <!--<tx:method name="del*" propagation="REQUIRED"/>-->
        </tx:attributes>
    </tx:advice>

    <!--配置aop增强-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="p" expression="execution(* icu.sunyanshu.service.BankServiceNo.account(..))"/>
        <!--配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="p"></aop:advisor>
    </aop:config>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值