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实例 | |
常用属性 | <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"/> |
重点API | ApplicationContext 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 用于导入其他配置类 | |
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) |
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) |
JdbcTemplate | tx:事务 JdbcTemplate自动提交事务 | 【使用步骤】 ① 在pom.xml导入 AOP 相关坐标 spring-jdbc spring-tx ② 创建数据库表与实体类 ③ 创建jdbc.properties配置文件 ④ 用Spring管理并创建JdbcTemplate对象 ⑤ 执行数据库操作(增删改查) |
事务控制-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层并测试 |
事务控制-注解 | 【使用步骤】 ① dao层 ② service层配置注解事务 ③ 配置applicationContext.xml |
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) | 黑马程序员IT技术论坛 X3.2 |