A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 大赟 初级黑马   /  2019-9-10 14:50  /  1102 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

了解掌握案例
Spring是什么轻量级 非侵入IOC  反转控制 把创建管理对象的权限交给spring
AOP  ⾯向切⾯编程 对方法、接口级别的拦截器,解耦
Spring快速⼊⻔1. 在pom.xml中导⼊Spring开发的基本包坐标 spring-context
2. 编写Dao接⼝和实现类
3. 在resources中创建Spring核⼼配置⽂件 applicationContext.xml
4. 把Dao交给Spring的Bean进⾏管理  依赖注入(又叫DI)   ①set方法注入  ②构造方法注入
5. 使⽤Spring的API获得Dao的Bean实例
4.依赖注入
    ①set方法注入

    private UserDao userDao
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

   【在 applicationContext.xml 中】
   <bean id="userDao" class="com.itheima.web.dao.impl.UserDaoImpl"></bean>
   
   <bean id="userService" class="com.itheima.web.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
   </bean>

   ②构造方法注入

    private UserDao userDao
    public UserServiceImpl() {
    }
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

   【在 applicationContext.xml 中】
   <bean id="userDao" class="com.itheima.web.dao.impl.UserDaoImpl"></bean>

    <bean id="userService" class="com.itheima.web.service.impl.UserServiceImpl">
        <constructor-arg name="userDao" ref="userDao"></constructor-arg>
    </bean>
常用属性<Bean>标签
    id属性:在容器中Bean实例的唯⼀标识,不允许重复
    class属性:要实例化的Bean的全限定名
    scope属性:Bean的作⽤范围,常⽤是Singleton(默认)和prototype
    <property>标签:set方法注入,属性注⼊
         name属性:setXxx()方法的Xxx,属性名称
         value属性:注⼊的普通属性值
         ref属性:注⼊的对象引⽤值
         <list>标签
         <map>标签
         <properties>标签
    <constructor-arg>标签
<import>标签:导⼊其他的Spring的分⽂件
    resource:引入其他文件的路径
加载外部jdbc.properties
<context:property-placeholder location="classpath:jdbc.properties"/>
重点APIApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
getBean("id")
getBean(Class)
Spring原始注解[注解]             [说明]
@Component         使用在类上用于实例化Bean
@Controller        使用在web层类上用于实例化Bean
@Service           使用在service层类上用于实例化Bean
@Repository        使用在dao层类上用于实例化Bean
@Autowired         使用在字段上用于根据类型依赖注入,如果只使用@Autowired,就只按种类选择
@Qualifier         结合@Autowired一起使用用于根据名称 id 进行依赖注入
@Resource          相当于@Autowired+@Qualifier,按照名 id 称进行注入
@Value             注入普通属性
@Scope             标注Bean的作用范围
@PostConstruct     使用在方法上标注该方法是Bean的初始化方法
@PreDestroy        使用在方法上标注该方法是Bean的销毁方法

[注解的组件扫描] - 一般扫描除controller层之外的
<context:component-scan base-package="com.itheima"></context:component-scan>
Spring新注解[注解]             [说明]
@Configuration     用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解
@ComponentScan     用于指定 Spring 在初始化容器时要扫描的包。 作用和在 Spring 的 xml 配置文件中的 <context:component-scan base-package="com.itheima"/>一样
@Bean              使用在方法上,标注将该方法的返回值存储到 Spring 容器中
@PropertySource    用于加载.properties 文件中的配置
@Import            用于导入其他配置类
@Configuration
@ComponentScan("com.itheima")
@Import({DataSourceConfiguration.class})
public class SpringConfiguration {
}

@PropertySource("classpath:jdbc.properties")
public class DataSourceConfiguration {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
}

@Bean(name="dataSource")
public DataSource getDataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;
}

@Test
public void testAnnoConfiguration() throws Exception {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.save();
DataSource dataSource = (DataSource) applicationContext.getBean("dataSource");
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
Spring整合Junit① 在pom.xml导入spring集成Junit的坐标 spring-context spring-test junit
② 自己新建一个测试类,类名上面使用 @Runwith(SpringJUnit4ClassRunner.class) 注解替换原来的运行期
③ 类名上面使用 @ContextConfiguration("classpath:applicationContext.xml") 或 @ContextConfiguration(classes = {被@Configuration指定配置类的类名.class})指定配置文件或配置类
④ 成员变量上面使用 @Autowired 注入需要测试的对象
⑤ 创建测试方法,上面使用 @Test 进行测试
AOP 相关概念底层:反射

[两种动态代理技术]
    JDK 代理   : 基于接口的动态代理技术
    cglib 代理 : 基于父类的动态代理技术

[相关术语]
   Target(目标对象):代理的目标对象
   Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
   Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
· Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
· Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知
· Aspect(切面):是切入点和通知(引介)的结合
· Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入

[切点表达式]
execution( [修饰符]  返回值类型  包名.类名.方法名(参数) )
例如:
execution(public void com.itheima.aop.Target.method())
execution(void com.itheima.aop.Target.*(..))
execution(* com.itheima.aop.*.*(..))    // 重点掌握这种
execution(* com.itheima.aop..*.*(..))
execution(* *..*.*(..))

[环绕增强方法]
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕前置增强...");
        Object proceed = pjp.proceed();
        System.out.println("环绕后置增强...");
        return proceed;
    }
【JDK动态代理(手写)】
Target target = new Target(); //创建目标对象
//创建代理对象
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass()
.getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
            System.out.println("前置增强代码...");
            Object invoke = method.invoke(target, args);
            System.out.println("后置增强代码...");
            return invoke;
        }
    }
);
proxy.method();

【cglib动态代理(手写)】
Target target = new Target(); //创建目标对象
Enhancer enhancer = new Enhancer();   //创建增强器
enhancer.setSuperclass(Target.class); //设置父类
enhancer.setCallback(new MethodInterceptor() { //设置回调
    @Override
    public Object intercept(Object o, Method method, Object[] objects,
    MethodProxy methodProxy) throws Throwable {
        System.out.println("前置代码增强....");
        Object invoke = method.invoke(target, objects);
        System.out.println("后置代码增强....");
        return invoke;
    }
});
Target proxy = (Target) enhancer.create(); //创建代理对象
proxy.method();
AOP-XML<aop:通知类型 method=“切面类中方法名” pointcut=“切点表达式"></aop:通知类型>
[通知标签类型]
前置通知        aop:before
后置通知        aop:after-returning
环绕通知        aop:around            
异常抛出通知    aop:after-throwing
最终通知        aop:after

[XML切点表达式的抽取]
<aop:pointcut id="myPointcut" expression="execution(* com.itheima.aop.*.*(..))"/>
<aop:before method="before" pointcut-ref="myPointcut"></aop:before>
【使用步骤】
① 在pom.xml导入 AOP 相关坐标  spring-context   aspectjweaver

② 创建目标接口和目标类(内部有切点)

③ 创建切面类(内部有增强方法)

④ 导入aop命名空间
         xmlns:context="http://www.springframework.org/schema/context"
         xmlns:aop="http://www.springframework.org/schema/aop"
   导入aop约束路径
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd

⑤ 在 applicationContext.xml 中
   使用标签 <bean> 将目标类和切面类的对象创建权交给 spring  
   使用标签 <aop> 配置织入关系

⑥ 测试代码(Spring整合Junit)
⑤ 使用标签 <bean> 将目标类和切面类的对象创建权交给 spring
       <bean id="target" class="com.itheima.aop.Target"></bean>       //  配置目标类
       <bean id="myAspect" class="com.itheima.aop.MyAspect"></bean>   //  配置切面类
   使用标签 <aop> 配置织入关系
       <aop:config>
           <aop:aspect ref="myAspect">
               <aop:pointcut id="myPointcut" expression="execution(* com.itheima.proxy.JDKproxy.Target.*(..))"/>
               <aop:before method="before" pointcut-ref="myPointcut"/>
               <aop:around method="around" pointcut-ref="myPointcut"/>
               <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
               <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>
               <aop:after method="after" pointcut-ref="myPointcut"/>
           </aop:aspect>
       </aop:config>
AOP-注解[通知注解类型]
前置通知        @Before
后置通知        @AfterReturning
环绕通知        @Around                 // 注意 配置环绕通知时,spring-context 与 aspectjweaver 1.8.4以下版本一起使用会引发jar包冲突
异常抛出通知    @AfterThrowing
最终通知        @After

[注解切点表达式的抽取]
    @Pointcut("execution(* com.itheima.aop.*.*(..))")  // 注意 若想使用@Pointcut注解,aspectjweaver最低版本是1.8.9
    public void myPoint(){};

    @Before("MyAspect.myPoint()")
    public void before(){
        System.out.println("前置代码增强.....");
    }
【使用步骤】
① 在pom.xml导入 AOP 相关坐标  spring-context   aspectjweaver

② 创建目标接口和目标类(内部有切点)

③ 创建切面类(内部有增强方法)

④ 导入aop命名空间
         xmlns:context="http://www.springframework.org/schema/context"
         xmlns:aop="http://www.springframework.org/schema/aop"
   导入aop约束路径
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd

⑤ 使用注解 @Component 将目标类和切面类的对象创建权交给 spring
   使用注解 @Aspect 标注切面类
   使用通知注解 如 @Before 等标注通知方法

   在 applicationContext.xml 中
      配置注解扫描的组件扫描
          <context:component-scan base-package="com.itheima"></context:component-scan>
      配置aop自动代理
          <aop:aspectj-autoproxy/>

⑥ 测试代码(Spring整合Junit)
JdbcTemplatetx:事务
JdbcTemplate自动提交事务
【使用步骤】
① 在pom.xml导入 AOP 相关坐标  spring-jdbc  spring-tx

② 创建数据库表与实体类

③ 创建jdbc.properties配置文件

④ 用Spring管理并创建JdbcTemplate对象

⑤ 执行数据库操作(增删改查)
④ 在 applicationContext.xml 配置文件中
<context:property-placeholder location="classpath:jdbc.properties"/>         // 读取jdbc.properties文件,注意,这里要引入context的命名空间
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">     // 数据源DataSource  
    <property name="driverClass" value="${jdbc.drvier}"></property>
    <property name="jdbcUrl" value="${jdbc.url}"></property>
    <property name="username" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">  // Spring管理JdbcTemplate
    <property name="dataSource" ref="dataSource"></property>
</bean>

⑤ 自定义一个测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdbcTemplateCRUDTest {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Test
    自定义增删改查方法 使用jdbcTemplate.update query 和sql语句
    }
事务控制-XML[4种隔离级别]
1. ISOLATION_READ_UNCOMMITTED:这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
2. ISOLATION_READ_COMMITTED:保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
3. ISOLATION_REPEATABLE_READ:这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
4. ISOLATION_SERIALIZABLE:这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。


脏读(针对未提交的事务):即事务A读到了事务B还没有提交的数据。如果事务A对数据进行了更新,但是事务A并没有提交,但是事务B这个时候看到了事务A没有提交的更新。当事务A进行了回滚,那么刚刚事务B看到的数据就是脏数据。也就是脏读。
例子:A 给 B 转了100万,但是 A 还没有提交,此时 B 查询自己账户,多了100万。然后 A 发现转错人了,回滚了事物。然后 B 100万就没了。在这个过程中 B 查到了没有提交的数据(多出的100万),这就是脏读。

不可重复读(在一个事务里面读取了两次某数据,读出来的数据不一致,针对修改操作):即同一事务在事务执行过程中对同一个数据进行了多次读取,但是每一次读取的数据结果都不相同。原因是在两次读取间隔,数据别其他人修改了,导致了统一事务两次读取结果不一致。
例子:A 查询银行余额为100万,B 这个时候取走了50万,此时余额变成了50万,A 再一次查询余额,变成了50万。对 A 而言两次结果不一致就是不可重复读。

幻读(在一个事务里面的操作中发现了为被操作的数据,针对增删操作):即在事务 A多次读取数据集的过程中中,事务 B 对数据进行了新增操作或者删除操作,导致事务 A多次读取的数据集不一致。
例子:A 修改当前公司所有职员信息的时候,B 向其中插入了一个新的职员,这个时候A 提交的时候发现了一个自己没有修改过的职员的信息,对 A 而言就像是产生了幻觉。

[7种传播行为]
1. REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
2. SUPPORTS:如果有事务,就会使用事务,如果没有,就不使用事务的方式执行。
3. MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
4. REQUERS_NEW:每次都会新建事务它与REQUIRED的区别在于事务的回滚程度,调用B时,即使A有事务,B也会自己开启一个事务,那么这样就是存在两个不同的事务,如果B已经提交事务,A发生异常会进行回滚,那么B也是不会回滚的,若B发生异常,A进行捕获B的异常后,B进行回滚,A可以正常提交事务并执行
5. NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
6. NEVER:以非事务方式运行,如果当前存在事务,抛出异常
7. NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行REQUIRED 类似的操作

[超时时间]:设置调用此方法的最大时间,超出则强行中断,不在进行查询

[是否只读]:声明此事务方法中只能做查询
【使用步骤】
① 在pom.xml导入 AOP 相关坐标  spring-context  aspectjweaver  spring-jdbc  spring-tx  spring-test  c3p0  mysql-connector-java  junit
② 创建实体和对应数据库
③ 创建持久层
④ 创建业务层
⑤ 配置applicationContext.xml
⑥ 创建Controller层并测试
⑤ 配置applicationContext.xml

<!--加载jdbc.properties-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
<!--数据源对象-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
<!--jdbc模板对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--管理dao层对象-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <property name="template" ref="jdbcTemplate"></property>
    </bean>
<!--目标对象  内部的方法就是切点-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
<!--配置平台事务管理器   理解为切面类-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
<!--通知  事务的增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--设置事务的属性信息的-->
        <tx:attributes>
            <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
<!--配置事务的aop织入-->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.itheima.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
事务控制-注解【使用步骤】
① dao层
② service层配置注解事务   
③ 配置applicationContext.xml
① dao层  
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    其他方法...
}

② service层配置注解事务  
@Service("accountService")
@Transactional        // 注解使用在类上,那么该类下的所有方法都使用同一套注解参数配置,属性同 xml 配置方式,例如隔离级别、传播行为等
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;
    @Transactional    // 注解使用在方法上,只有此方法用这个注解的配置,就近原则
    业务方法...
}

③ 配置applicationContext.xml
<!--注解组件扫描-->  
    <context:component-scan base-package="com.itheima"/>
<!--事务的注解驱动,开启并识别事务注解 transaction-manager="平台事务管理器id"-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马