框架学习基本上是学习框架的使用,所以是以记忆为主要的,当然如果有些时候你想知道为什么要这么使用去深入研究也是可以的。但是不要浪费太多时间,大多数小白还没有到读框架源码的水平,所以做到理解和运用就很好了。
问题1:Component name “login” should always be multi-word vue/multi-word-component-names
就是组件名不能为一个单词的问题
解决方法:
方法一:可以把组件名写成驼峰命名,如把login 改成 loginIn
方法二:可以在vue.config.js中加入lineOnSave:false
问题2:通配符的匹配很全面, 但无法找到元素 context:component-scan 的声明。
就是导入的声明不全,导入的声明需要下面这三条
解决方法:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
心得:注意版本问题,编译器版本和框架版本和服务器和各种工具包的版本问题。有些新的软件如jdk会对不支持一些旧的框架,这样就会莫名其妙的报一堆的错误。
Jar包的引用,当你学习一个框架的时候,当你学习不同版本的框架的时候,你要去百度一下需要哪jar包,每个jar包大概干什么用的,这个真的非常重要,jar包不对,后面就会出现一系列的错误。
有哪些依赖包。
Jar包大概分为这么几类。
日志框架jar包
数据源jar包(管理数据库)
一些工具包,给java提供一些功能拓展。
一些升级或者是删改
不同的版本中,在配置文件的同一个位置去配置一个类的时候,这个类的路径有可能会发生变化。
有时候配置一些驱动之类的,或者是其他的一些配置都有可能会不同
有的时候是出现了个新的功能,你需要增加一些配置,有的时候是删减了一些类,你再次引用的时候发现这个类已经不存在了。
总而言之,如果你看的教程用的版本和你电脑的版本不太一样,而且你不愿意换的话,你最好去百度一下,这两个版本有什么不同,和这新版本应该怎么配置。(你学习旧版本的时候已经基本上理解了框架,当你学习新版本的时候,你只需要稍微修改一下配置就可以了。)
注意配置文件的一些细节,当你怎么也检查不出来配置文件的错在哪里的时候,你可以选择复制别人的一份代码,然后调试别人的代码,把他调试到能够使用(因为别人的代码很小的几率会在你犯错并且检查不出来的地方也犯了一个和你一样的错误。)以下是我学习过程的笔记
Spring简介
分层的Java SE/EE应用full-stack轻量级开源框架,以IOC(反转控制)和AOP(面向切面编程)为内核
能整合开源世界众多第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架
优势:
方便解耦:通过IOC容器,将对象间的依赖关系交给Spring控制,避免编码的过度耦合
AOP编程的支持
声明式事务支持:声明式灵活管理事务,减少不必要的事务管理的代码编写
方便测试
方便集成优秀框架
降低对Java EE API的使用难度
源码是学习典范
Spring基本开发步骤:
导入jar包坐标
创建Javabean
创建配置文件applicationContext.xml
配置文件种进行配置
创建ApplicationContext对象调用getBean()方法
Spring的IOC开发
Spring配置文件
Bean标签基本配置
用于配置的对象交给spring创建,默认情况下调用类中的无参构造,如果没有则创建失败
基本属性:
id:Bean实例在Spring容器中的唯一标识
class:Bean的全限定名称
其他属性:
scope:对象的作用范围,singleton(单例的,默认值),prototype(多例的),request,session,global session
当scope属性为singleton时:
实例化时机:Spring核心文件被加载时(配置文件被加载时)
当scope属性为prototype时:
实例化时机:调用getBean()时
init-method:指定类中的初始化方法名称
destroy-method:指定类中的销毁方法名称
Bean实例化三种方式:
无参构造方法实例化(掌握):<bean id="userDao" class="com.itheima.domain.User"/>
工厂静态方法实例化(了解):
public class StaticFactoryBean{ public static UserDao createUserDao(){ return new UserDaoImpl(); } }
<bean id="userDao" class="com.itheima.factory.StaticFactoryBean" factory-method="createUserDao" />
工厂实例化方法实例化(了解):
public class DynamicFactoryBean{ public UserDao createUserDao(){ return new UserDaoImpl(); } }
<bean id="factoryBean" class="com.itheima.factory.DynamicFactoryBean"/> <bean id="userDao" factory-bean="factoryBean" factory-method="createUserDao"/>
Bean的依赖注入入门:
创建UserService,UserService内部调用UserDao的save()方法;
将UserServiceImpl的创建全交给Spring
从Spring容器中获得UserService进行操作
分析:因为UserService和UserDao都在Spring容器中,而最终程序直接使用的是UserService,所以可以在Spring容器中,将UserDao设置到UserService内部。
Bean的依赖注入方式:
1.set方法注入:
UserServiceImpl
//在UserServiceImpl中添加setUserDao方法
pubic class UserServiceImpl implements UserService{
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
applicationContext.xml
property 的 name 属性代表的是 userService 中 set 方法的后半段也就是 userDao
<!--在配置文件中配置-->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<!-- name是set方法后半段的对应名字,ref是配置文件中的其他引用id -->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
Controller
public class UserController {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) app.getBean("userService");
userService.save();
}
}
注意:此时将UserDao的创建权交给了Spring,如果Controller层没有通过Spring配置文件创建UserService,而是通过自己new 一个 UserService,此时自己new 的UserService内部将没有通过set方法创建和注入DaoUser对象,因此使用UserDao.save方法会产生空指针异常
p命名空间注入(了解,属于set方式)
扩展:引入p命名空间写法,一般不常用
<!-- 引入p命名空间-->
xmlns:p="http://springframework.org/schema/p"
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<!-- 修改注入方式,p:userDao-ref=引用的 Bean id-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl" p:userDao-ref="userDao"/>
2.构造方法注入:
创建有参构造
<!-- 配置spring容器调用有参构造时进行注入-->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<constuctor-arg name="userDao" ref="userDao"/>
</bean>
Bean的依赖注入的数据类型(这里都是使用set方式)
1.普通数据类型
例如String,在UserDaoImpl创建私有对象name和age,创建set方法
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="name" value="zhangsan"/>
<property name="age" value="18"/>
</bean>
2.引用数据类型(上面已有)
3.集合数据类型
例如list<String>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="strList" value="zhangsan">
<list>
<value>123</value>
<value>123</value>
<value>123</value>
</list>
</property>
</bean>
例如map<String,User>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="userMap">
<map>
<entry key="u1" value-ref="user1"></entry>
<entry key="u2" value-ref="user2"></entry>
</map>
</property>
</bean>
<bean id="user1" class="com.itheima.domain.User">
<property name="name" value="zhangsan"></property>
<property name="addr" value="changsha"></property>
</bean>
<bean id="user2" class="com.itheima.domain.User">
<property name="name" value="lisi"></property>
<property name="addr" value="sichuan"></property>
</bean>
例如properties <String,String>类型的键值对
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="props">
<props>
<prop key="p1">aaa</prop>
<prop key="p2">bbb</prop>
</props>
</property>
</bean>
引入其他配置文件,分模块开发:
<import resource="applicationContext-xxx.xml"/>
可以在主配置文件中通过import引入其他配置文件
如果配置发生冲突,按照配置引入的先后顺序进行覆盖
简单记忆
注意:配置文件中property的name
用set方法注入,name:set方法后半段的属性值 (setUserDao => userDao)
用构造方法,name:要传入的参数名 (传入userDao => userDao)
依赖注入引用对象:配置 ref 属性
依赖注入普通对象:配置 value 属性 (String类型也是直接配value)
依赖注入普通对象如果是集合类型,要根据集合类型配置不同属性
如:List类型的注入 要配置<list>属性,list属性中再配置相应对象;Map类型的注入 要配置<Map>属性,其中由键值对组成,所以再配<entry>属性
Spring相关API
ApplicationContext:接口类型,代表应用上下文,可以通过实例获得Spring容器中的Bean对象
ApplicatioContext实现类:
ClassPathXmlApplicationContext:从类的根路径下加载配置文件,推荐使用
FileSystemXmlApplicationContext:从磁盘路径上加载配置文件,配置文件可以在磁盘任意位置,不常用
AnnotationConfigApplicationContext:使用注解配置容器对象时,使用此类来创建Spring容器,同来读取注解
getBean()方法:
参数类型为String时,标识根据Bean的id从容器中获得Bean实例,返回Object
参数类型为Class类型时,根据类型从容器中获取Bean实例,不能用于容器中有多个相同类型的Bean
Spring配置数据源(连接池)
开发步骤:
导入数据源坐标和数据库驱动坐标
创建数据源对象
设置数据源的基本连接数据
使用数据源获取连接资源和归还连接资源
原始方式配置数据源(未解耦)
//不使用配置文件
@Test
public void testDruid() throw Exception{
//创建数据源
DruidDataSource dataSource = new DruidDataSource();
//设置数据库连接参数
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("root");
//获得连接对象
DruidPooledConnection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
读取jdbc.properties配置文件创建连接池(解耦,但没有让spring帮我们创建数据源对象)
//读取jdbc.properties配置文件创建连接池
@Test
public void test2() throws SQLException {
//加载类路径下的jdbc.properties配置文件
ResourceBundle rb = ResourceBundle.getBundle("jdbc");
//创建druid数据源对象
DruidDataSource dataSource = new DruidDataSource();
//设置驱动,url,username,password
dataSource.setDriverClassName(rb.getString("driver"));
dataSource.setUrl(rb.getString("url"));
dataSource.setUsername(rb.getString("username"));
dataSource.setPassword(rb.getString("password"));
//获取连接对象
DruidPooledConnection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
7
使用Spring配置数据源
将DataSource的创建权交给Spring容器去完成(解耦合,但同时配置文件分工不够明确)
DataSource有无参构造方法,Spring时默认通过无参构造方法实例化对象
DataSource还需要通过set方法设置数据库连接信息,Spring可以通过set方法注入
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
//测试从容器中获取数据源
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource)app.getBean("dataSource");
Connection connection = dataSource.getConnection();
System.out.println(connection);
抽取jdbc配置文件配置数据源
(解耦合,同时每个配置文件分工明确,数据库配置 和 spring配置分开了)
applicationContext.xml加载jdbc.properties配置文件获得连接信息
location="类加载路径:xxx.properties"
<!-- 在beans引入context命名空间和约束路径-->
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
<!-- 加载jdbc.properties配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 使用SpEL将配置文件中的value赋进去-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
Spring注解开发(主流 重要)
注解代替xml配置
步骤:
先在类中加上注解
开启组件扫描
spring原始注解
使用注解开发时:需要在applicationContext.xml中配置组件扫描,作用时指定那个包及其子包下的Bean需要进行扫描以便试别需要使用注解配置的类,字段和方法
<!-- 注解组件扫描-->
<context:component-scan base-package="com.itheima"/>
使用@Component或者@Repository标识UserDaoImpl进行Spring实例化
//<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
//@Component("userDao")
@Repository("userDao")
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("save running...");
}
}
使用@Component或者@Service标识UserServiceImpl进行Spring实例化
使用@Value进行字符串的注入
使用@Autowired或者@Autowired+@Qualifier或者@Resource进行userDao的注入
(使用注解注入可以不需要set方法,直接通过反射给目标赋值)
//<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
//@Component("userService")
@Service("userService")
public class UserServiceImpl implements UserService {
//使用@Value进行字符串的注入
@Value("${jdbc.driver}")
private String driver;
private UserDao userDao;
//<property name="userDao" ref="userDao"></property>
//@Autowired //只写Autowired时,是按照数据类型从Spring容器中匹配的
//@Qualifier("userDao") //Autowired+Qualified是按照id值从Spring容器中匹配的
@Resource(name = "userDao")
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save() {
System.out.println(driver);
userDao.save();
}
}
使用Scope标注Bean的范围
@Scope("singleton")
public class UserDaoImpl implements UserDao{
}
注意
在要依赖注入属性前只写Autowired时,是Spring按照该数据类型从Spring容器中匹配的,
例如:当前需要一个userDao对象,然后Spring中正好将UserDaoImpl默认singleton注入了,所以就可以使用,但如果有多个对象,就会出问题
即:按照类型注入:@Autowired;按照 id 注入:@Autowired + @Qualifier("xxx")
使用注解注入对象可以不需要set方法,直接通过反射找到目标对象,给目标赋值
@Value("${jdbc.driver}")Value一般配合SpEL使用,来注入Spring配置文件中的一些普通变量
Spring新注解
使用原始注解还不能全部代替xml文件,还需要新注解
非自定义的Bean配置:<bean>
加载properties文件的配置:<context:property-placeholder>
扫描组件的配置:<context:component-scan>
引入其他文件:<import>
@Configuration //指定该类是Spring配置类,加载该类的注解
//<context:component-scan base-package="com.itheima"/>
@ComponentScan("com.itheima") //指定扫描组件的配置
@Import({DataSourceConfiguration.class}) //导入其他配置类,是个数组
public class SpringConfiguration {
}
@Configuration
//<context:property-placeholder location="classpath:jdbc.properties"/>
@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") //将改方法的返回值存放到Spring容器中
public DataSource getDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
测试类要使用AnnotationConfigApplicationContext类指定配置类名称,获得ApplicationContext对象
public class controller {
public static void main(String[] args) {
ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = app.getBean(UserService.class);
userService.save();
}
}
Spring集成Junit
每个测试类中,每个测试方法都会有下面两行代码
ApplicationContext app = new ClassPathXmlApplicationContext("bean.xml");
Object o = app.getBean(xxx.class);
1
2
这两行的代码作用是获取容器,不写的话,提示空指针异常,所以不能轻易删掉
解决思路:让SpringJunit负责创建Spring容器,但是需要将配置文件名字告诉它,将需要进行测试的bean直接在测试类中注入
Spring继承Junit步骤:
导入Spring集成Junit的坐标:<artifactId>spring-test</artifactId>
使用@Runwith注解替换原来的运行期
使用@ContextConfiguration指定配置文件或配置类
使用@Autowired注入需要测试的对象
使用@Test创建方法进行测试
//使用@Runwith注解替换原来的运行期
@RunWith(SpringJUnit4ClassRunner.class)
//使用@ContextConfiguration指定配置文件或配置类
@ContextConfiguration("classpath:applicationContext.xml")
//@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
@Autowired
private UserService userService;
@Autowired
private DataSource dataSource;
@Test
public void test1() throws SQLException {
System.out.println(dataSource.getConnection());
userService.save();
}
}
Spring的AOP开发
面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的技术
优点:在程序运行期间不修改源码的情况下进行功能增强,减少重复代码,提高效率便于维护
实现:底层通过Spring的动态代理技术实现
常用动态代理技术:
JDK代理:基于接口的动态代理技术
cglib代理:基于父类的动态代理技术
JDK动态代理
//目标类接口
public interface TargetInterface {
public void save();
}
//目标类
public class Target implements TargetInterface{
public void save() {
System.out.println("save running....");
}
}
//增强类的增强方法
public class Advice {
public void before(){
System.out.println("前置增强");
}
public void after(){
System.out.println("后置增强");
}
}
//动态代理代码
public class ProxyTest {
public static void main(String[] args) {
//目标对象
final Target target = new Target();
//增强对象
final Advice advice = new Advice();
TargetInterface proxyInstance = (TargetInterface) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.before();
Object invoke = method.invoke(target, args);
advice.after();
return invoke;
}
}
);
//代理对象的方法测试
proxyInstance.save();
}
}
cglib动态代理
//目标类
public class Target {
public void save() {
System.out.println("save running....");
}
}
//增强类的增强方法
public class Advice {
public void before(){
System.out.println("前置增强");
}
public void after(){
System.out.println("后置增强");
}
}
//动态代理代码
public class ProxyTest {
public static void main(String[] args) {
final Target target = new Target();
final Advice advice = new Advice();
//返回值就是动态生成的代理对象,基于cglib
//创建增强器
Enhancer enhancer = new Enhancer();
//设置父类(目标)
enhancer.setSuperclass(Target.class);
//设置回调
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] obj, MethodProxy methodProxy) throws Throwable {
advice.before();
Object invoke = method.invoke(target, obj);
advice.after();
return invoke;
}
});
//创建代理对象
Target proxy = (Target) enhancer.create();
//测试代理方法
proxy.save();
}
}
AOP相关概念
Spring的AOP实现底层就是对上面的动态代理代码进行了封装
AOP相关术语:
Target(目标对象):要代理的目标对象
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
Joinpoint(连接点):被拦截到的方法,可以被增强的方法
Pointcut(切入点):要被增强的方法,实际被增强的方法
Advice(通知、增强):增强方法
Aspect(切面):Pointcut+Advice
Weaving(织入):动态代理的过程
AOP底层使用哪种代理方式:Spring中,会根据目标类是否实现了接口来决定采用哪种方式
开发明确:
谁是切点(切点表达式的配置)
谁是通知(切面类中的增强方法)
将切点和通知进行织入配置
基于XML的AOP开发快速入门
步骤:
导入AOP相关坐标(aspectj)
创建目标接口和目标类(内部有切点)
创建切面类(内部有增强方法)
将目标类和切面类的创建权交给Spring
在applicationContext.xml中配置织入关系
测试
导入AOP相关坐标
<!--cglib等在context中-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--使用AspectJ的织入-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
创建目标接口和目标类
public interface TargetInterface {
public void save();
}
public class Target implements TargetInterface {
public void save() {
System.out.println("save running....");
}
}
创建切面类(内部有增强方法)
public class MyAspect {
public void before(){
System.out.println("前置增强....");
}
public void afterReturning(){
System.out.println("前置增强....");
}
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前增强....");
Object proceed = pjp.proceed();
System.out.println("环绕后增强....");
return proceed;
}
public void afterThrowing(){
System.out.println("异常抛出增强....");
}
public void after(){
System.out.println("最终增强....");
}
}
将目标对象和切面对象的创建权交给Spring
<!--目标对象-->
<bean id="target" class="com.itheima.aop.Target"></bean>
<!--切面对象-->
<bean id="myAspect" class="com.itheima.aop.MyAspect"></bean>
在applicationContext.xml配置织入关系
<!--先配置aop命名空间-->
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
<!--配置切点表达式和和增强的织入关系-->
<!--配置织入:告诉spring框架 哪些方法(切点)需要进行增强(前置,后置....)-->
<aop:config>
<!--引用myAspect的Bean作为切面对象-->
<aop:aspect ref="myAspect">
<!--配置Target的save方法执行时要被myAspect的before方法前值增强-->
<aop:before method="before" pointcut="execution(public void com.itheima.aop.Target.save())"/>
</aop:aspect>
</aop:config>
XML配置AOP详解
切点表达式写法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
注意:
修饰符可以省略
除开修饰符都可以用星号 * 表示任意
包名与类名之间一个点.表示当前包下的类,两个点..表示当前包及其子包下的类
参数列表可以用两个点..表示任意个数,参数类型的参数列表
常用:execution(* com.itheima.aop .*.*(..))
通知的配置语法:<aop:通知类型 method="切面类中方法名" pointcut="切点表达式" />
切点表达式的抽取
当多个切点表达式相同时,配置pointcut-ref属性进行抽取
<aop:pointcut id="myPointcut" expression="execution(* com.itheima.aop.*.*(..))"/>
<aop:before method="before" pointcut-ref="myPointcut"/>
基于注解的AOP配置
通知的配置语法:@通知注解(“切点表达式”)
步骤:
前置步骤:用@Component将 切面类 和 目标类 交给Spring创建,同时开启组件扫描
使用@Aspect标注切面类
使用@增强类型注解标注通知方法
在配置文件中配置aop自动代理<aop:aspectj-autoproxy>
将目标类和切面类的对象创建权交给Spring(使用注解)
在切面类中使用注解配置织入关系
@Component("target")
public class Target implements TargetInterface {
public void save() {
System.out.println("save running....");
}
}
@Component("myAspect")
//告诉Spring这是切面类
@Aspect
public class MyAspect {
//配置织入关系
@Before("execution(* com.itheima.anno.*.*(..))")
public void before(){
System.out.println("前置增强....");
}
}
在配置文件中开启组件扫描和AOP自动代理
<!-- 组件扫描-->
<context:component-scan base-package="com.itheima.anno"/>
<!-- aop自动代理-->
<aop:aspectj-autoproxy/>
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-anno.xml")
public class AnnoTest {
@Autowired
private TargetInterface targetInterface;
@Test
public void test1(){
targetInterface.save();
}
}
解耦:切面类中,切点表达式的抽取
@Component("myAspect")
@Aspect
public class MyAspect {
@Before("pointcut()")
public void before(){
System.out.println("前置增强....");
}
@Pointcut("execution(* com.itheima.anno.*.*(..))")
public void pointcut(){}
}
Spring JdbcTemplate基本使用
要导入 spring-jdbc 和 spring-tx 坐标依赖
使用Spring配置创建jdbcTemplate对象 模板
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
>
<!--使用context命名空间,引入jdbc.properties-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--创建数据源对象-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--依赖注入数据源对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root
jdbcTemplate 常用方法
int row = update(sql, ...args)常用于 add delete update 操作,返回影响的行数
List<?> list= query(sql, new BeanRowMapper<?>()) 常用于查询多条记录,返回 list 集合
Object o = queryForObject(sql, new BeanRowMapper<Object>()) 常用于查询单行,返回一个指定对象
Long count = queryForObject(sql, Long.class) 用于查询记录的数量,返回数量(可以是Integer或者Long)
Spring的事务控制
编程式事务控制
三大对象
PlatformTransactionManager:平台事务管理接口
实现是根据不同的Dao层的技术而实现的,不同的平台事务管理器内部封装的控制事务的方式,API 都不一样,(需要通过配置的方式指定)
TransactionDefinition:事务定义对象,封装一些事务的参数
隔离级别,传播行为 (需要通过配置的方式指定)
TransactionStatus:事务状态
随着事件的进行,内部的信息会跟着相应的改变 (不需要通过配置的方式改变)
声明式事务控制
作用:不侵入开发的组件,类似于AOP思想,通过在系统层面配置事务控制来控制业务逻辑,使 业务逻辑 和 事务控制 分开,降低耦合,改变事务时,也只需要在配置文件中更改即可。
Spring中声明式事务控制底层就是AOP
基于xml的声明式事务控制
步骤:
前置步骤:配置dataSource和jdbcTemplate,还有 AccountDaoImpl 以及 AccountServiceImpl
配置平台事务管理器 (要依赖于dataSource)
配置增强 (指定事务管理器,指定每个被事务控制的方法事务属性 如:隔离级别、传播行为等)
配置织入 (使用aop:advisor,因为事务控制只有一种增强)
<!--配置平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置增强-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED" timeout="-1" read-only="false" />
</tx:attributes>
</tx:advice>
<!--配置织入-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.itheima.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
<!--开启组件扫描-->
<context:component-scan base-package="com.itheima"/>
<!--配置平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--事务注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>