9. Spring

作者: Plenari | 来源:发表于2020-03-08 21:20 被阅读0次

    IOC

    • 由于java 编译后才能运行,由于编译期进行的检查可能导致我们缺组件不能编译通过。所以要想个办法绕过编译器的检测,所以反射就引用而生。编译完成后不能修改参数,所以配置文件应用而生。

    • 有些时候对象需要重复调用,这个时候需要一个容器存着可以调用对象。这个就是bean。以前都是自己new对象,现在是向bean要对象。所以称为控制反转。

    • 所以有对象创建对象获取两类。最后还包括main函数的运行。

    • main函数获取容器里对象的方法

    BeanFactory 才是 Spring 容器中的顶层接口。
    ApplicationContext 是它的子接口。
    BeanFactory 和 ApplicationContext 的区别:
    创建对象的时间点不一样。
    ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
    BeanFactory:什么使用什么时候创建对象。
    
    
    ApplicationContext 常用三个实现类:
         ClassPathXmlApplicationContext:
        它是从类的根路径下加载配置文件 推荐使用这种
        FileSystemXmlApplicationContext:
        它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
        AnnotationConfigApplicationContext:
        当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。
    
    
    
    spring架构图

    xml 对象创建

    - 创建方法
    <bean id="" class=""  scope=""></bean>
    id:给对象在容器中提供一个唯一标识。用于获取对象。
    class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
    scope:指定对象的作用范围。
    * singleton :默认值,单例的.
    * prototype :多例的.
    * request :WEB 项目中
    
    <!-- 告知 spring 创建容器时要扫描的包 -->
    <context:component-scan base-package="com.itheima"></context:component-scan>
    - 构造方法
    <!--构造函数constructor-arg-->
    <!--set 注入property-->
    <property name="password" value="1234"></property>
    <property name="password" ref="引用一个定义"></property>
    
    - 同样可以注入集合setmap
    
    
    <property name="myList">
    <array>
    <value>AAA</value>
    <value>BBB</value>
    <value>CCC</value>
    </array>
    </property>
    
    
    其中 list 对应array
    set对应list
    props对应map
     如何注入变量呢?
    

    注解创建对象

    • 创建对象
      @Component(value="name")将当前类注入到spring容器。默认将首字母改成小写的。与<bean id="" class="">一样
    他们三个注解都是针对一个的衍生注解,他们的作用及属性都是一模一样的。因为只有具体类可以实例化,所以这里肯定也是可以实例的类。他们只不过是提供了更加明确的语义化。
    @Controller:一般用于表现层的注解。
    @Service:一般用于业务层的注解。
    @Repository:一般用于持久层的注解。
    细节:如果注解中有且只有一个属性要赋值时,且名称是 value,value 在赋值是可以不写。
    
    • 注入数据
    
    - 只能注入其他 bean 类型。
    @Autowired  
    自动按照类型注入。当使用注解注入属性时,set 方法可以省略。它只能注入其他 bean 类型。当有多个类型匹配时,使用要注入的对象变量名称作为 bean 的 id,在 spring 容器查找,找到了也可以注入成功。找不到就报错。
    
    @Qualifier
    参数是名字,通过名字获取变量数据。。必须在autowired之后。
    @Resource
    
    
    
    // 注入基本数据类型和 String 类型数据的
    @Value
    @scope
    singleton
    prototype
    
    
    • 改变作用范围
    @Scope
    取值:singleton prototype request session globalsession
    
    • getBean('impl',class)???
      id,强制类型转换的类型

    • 注入数据顺序
      Autowired

    image.png

    Configuration

    指定该类的spring配置类,被指定路径引入时可以省略。

    获取容器时需要使用
    AnnotationApplicationContext(有@Configuration 注解的类.class)
    @ComponentScan("")
    指定需要扫描的包
    @PropertySource
    property配置文件
    
    @Bean(name="")
    只能用于方法上,表明此方法创建一个对象放入容器
    
    @Import
    引入其他配置类
    

    -写property文件

    public class JdbcConfig {
        
       @Value("${jdbc.driver}")
        private String driver;
        
        @Value("${jdbc.url}")
        private String url;
        
        @Value("${jdbc.username}")
        private String username;
        
        @Value("${jdbc.password}")
        private String password;
    
    //这样就可以存入spring容器里了。
    @Bean(name="dataSource")
    public DataSource createDataSource() {
    }
    
    
    }
    
    //jdbc.properties 文件:
      jdbc.driver=com.mysql.jdbc.Driver
      
     jdbc.url=jdbc:mysql://localhost:3306/day44_ee247_spring
    
    • 实例代码


      image.png
    • 通过注解获取容器
    ApplicationContext ac =
    new AnnotationConfigApplicationContext(SpringConfiguration.class);
    
    • Spring 整合Junit
    2.使用@RunWith 注解替换原有运行器
    3.使用@ContextConfiguration 指定 spring 配置文件的位置
    4.使用@Autowired 给测试类中的变量注入数据
    
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations= {"classpath:bean.xml"})
    public class AccountServiceTest {
    @Autowired
    private IAccountService as ;
    }
    
    

    AOP

    Aspect oriented Programming
    实现方式:动态代理的方式。典型应用事务管理,日志管理。

    • 使用CGlib 的Enhancer 类创建代理对象

    • Proxy.newProxyInstance

    • Spring自带的AOP细节

    • sprin术语

    Joinpoint(连接点):
    所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。

    Pointcut(切入点):
    所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。对连接点的定义是切入点。

    Advice(通知/增强):
    所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

    Introduction(引介):
    引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field。

    Target(目标对象):
    代理的目标对象。

    Weaving(织入):
    是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。

    Proxy(代理):
    一个类被 AOP 织入增强后,就产生一个结果代理类。

    Aspect(切面):
    是切入点和通知(引介)的结合。

    • 1.配置
    <!-- 配置通知 -->
    <bean id="txManager" class="com.itheima.utils.TransactionManager">
    <property name="dbAssit" ref="dbAssit"></property>
    </bean> 
    
    • 2.声明aop
    <aop:config>
    ...........
    </aop:config>
    
    • 3.配置切面
    <aop:aspect id="txAdvice" ref="txManager">
    <!--配置通知的类型要写在此处-->
    </aop:aspect>
    ref 引用已经配置好的通知类bean的id
    
    • 4.配置切入点表达式
    <aop:pointcut expression="execution(
    public void com.itheima.service.impl.AccountServiceImpl.transfer(
    java.lang.String, java.lang.String, java.lang.Float)
    )" id="pt1"/>
    
      1. 配置具体的通知
    <aop:before method="方法" pointct-ref="引用切入点表达式">
    
      1. 代码
    <aop:config>
        <aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))"id="pt1"/>
        <aop:aspect id="txAdvice" ref="txManager">
            <!-- 配置环绕通知 -->
            <aop:around method="transactionAround" pointcut-ref="pt1"/>
        </aop:aspect>
    </aop:config>
    
    

    使用注解方式实现aop

      1. 创建通知类,声明为切面类
    @Component("txManager")
    @Aspect//表明当前类是一个切面类
    public class TransactionManager {
        //定义一个 DBAssit
        @Autowired
        private DBAssit dbAssit ;
    }
    
    
    • 2.在 spring 配置文件中开启 spring 对注解 AOP 的支持
      <aop:aspectj-autoproxy/>
    • 3.切面表达式
    @Pointcut("execution(* com.itheima.service.impl.*.*(..))")
    private void pt1() {
    }
    
    
    • 4.定义通知
    @Around("pt1()")//注意:千万别忘了写括号
    public Object transactionAround(ProceedingJoinPoint pjp) {
        //怎么获得函数的名字
        //定义返回值
        Object rtValue = null;
        try {
            //获取方法执行所需的参数
            Object[] args = pjp.getArgs();
            //前置通知:开启事务
            beginTransaction();
            //执行方法
            rtValue = pjp.proceed(args);
            //后置通知:提交事务
            commit();
          }catch(Throwable e) {
            //异常通知:回滚事务
            rollback();
            e.printStackTrace();
          }finally {
            //最终通知:释放资源
            release();
          }
        return rtValue;
    }
    
    

    环境搭建

    • 在配置文件中导入 context 的名称空间

    jdbcTemplate

    1. aop 和tx命名空间
    2. 实体类,编写业务层接口和实现类
    3. 持久层和实现类
    4. 在配置文件中配置业务层和持久层对
       <!-- 配置业务层-->
        <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"></property>
        </bean>
    
        <!-- 配置账户的持久层-->
        <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
    
        <!-- 配置数据源-->
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql://localhost:3306/eesy"></property>
            <property name="username" value="root"></property>
            <property name="password" value="1234"></property>
        </bean>
    
        <!-- spring中基于XML的声明式事务控制配置步骤
            1、配置事务管理器
            2、配置事务的通知
                    此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的
                    使用tx:advice标签配置事务通知
                        属性:
                            id:给事务通知起一个唯一标识
                            transaction-manager:给事务通知提供一个事务管理器引用
            3、配置AOP中的通用切入点表达式
            4、建立事务通知和切入点表达式的对应关系
            5、配置事务的属性
                   是在事务的通知tx:advice标签的内部
    
         -->
        <!-- 配置事务管理器 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
        <!-- 配置事务的通知-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <!-- 配置事务的属性
                    isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
                    propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
                    read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
                    timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
                    rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
                    no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
            -->
            <tx:attributes>
                <tx:method name="*" propagation="REQUIRED" read-only="false"/>
                <tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
            </tx:attributes>
        </tx:advice>
    
        <!-- 配置aop-->
        <aop:config>
            <!-- 配置切入点表达式-->
            <aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut>
            <!--建立切入点表达式和事务通知的对应关系 -->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
        </aop:config>
    
    
    • spring-framework-5.0.02.RELEASE
    • xmlns
    • xsi
    • xsi:schemaLocation

    相关文章

      网友评论

          本文标题:9. Spring

          本文链接:https://www.haomeiwen.com/subject/nnomhhtx.html