Spring基础内容
1.Spring是什么?
- spring是一个分层的轻量级的全栈轻量级开源框架(全栈指的是各个层都有相应的处理方案),以ioc和aop为内核。提供了展现层springmvc和持久层spring jdbctemplate以及业务层事务管理等众多企业级应用技术,还整合了开源世界中众多的优秀的第三方类库,逐渐成为使用最多的javaee企业应用开源框架。
2.spring的优势
方便解耦,简化开发
AOP编程的支持
声明式事务的支持
方便程序的测试
方便集成各种优秀的框架
降低javaee api(jdbc、Java mail 、远程调用)的使用难度
java源码经典学习典范
3.spring体系结构
spring最下层是spring的核心容器包括四部分:beans,core,context,spEl(spring express language)
4.spring快速入门
-
思考:之前不同的类之间调用通过创建实例对象的方式进行调用,这样就增加了程序间的耦合度,因此我们需要使用spring来解决这一问题,将所有的类都交由spring进行管理。
开发步骤
1.导入spring坐标(spring-context)
2.编写dao接口和实现类
3.创建spring核心配置文件(在resource中创建application-context.xml)
4.在spring的配置文件中配置实现类
5.使用spring的api获取Bean实例(ClassPathXmlApplicationContext加载xml文件之后使用getbean获取bean对象调用方法即可)。
ApplicationContext app=new ClassPathXmlApplicationContext("application-context.xml");
app.getBean("自己起的标识类名");//此处就获取到了bean对象
5.spring配置文件详解
-
5.1bean标签的基本配置
用于配置对象交由spring来创建
默认情况下他调用的类是无参构造函数,如果没有无参构造则创建不成功。
-
基本属性
id:bean实例在spring容器中的唯一标识
class:bean的全限定类名
-
5.2bean标签的范围配置
socpe:指对象的作用范围。
注意:singleton使用空参构造进行初始化且执行一次(创建一次bean对象),prototype使用空参构造进行初始化,且执行多次(每获取一次bean对象创建一次bean),不用时被gc回收。
-
取值范围 说明 singleton 默认,单例 prototype 多例的(每次getbean都会创建一个新的对象) request web项目中,spring创建一个bean对象,将对象存入request域中 session web项目中,spring创建一个bean对象,将对象存入session域中 global session web项目中,应用portlet环境。如果没有portlet环境,该范围就相当于session
-
5.3bean的生命周期配置
init-method:指类中的初始化方法名称(在xml文件的bean中配置init-method对应执行的方法)
destroy-method:指类中销毁方法名称(在xml文件的bean中配置destory-method对应执行的方法)
bean的生命周期包括:初始化、创建、销毁
-
5.4bean实例化的三种方式
-
无参构造方法实例化
-
无参构造方式实例化步骤:
1.编写dao接口和实现类
2.创建spring配置文件application-context.xml并配置bean
3.在测试类中调用api接口加载配置文件,获取bean调用方法即可。
-
-
工厂静态方法实例化
-
工厂静态方法实例化步骤:
1.创建静态工场类的静态方法,返回实现类。
2.创建application-context.xml,定义bean在里面写factory-method=“方法名”。
3.在测试类中调用ClassPathXmlApplicationContext加载spring的xml文件,之后getBean后,调用对应的方法即可。
-
-
工厂实例方法实例化
-
工厂实例方法实例化步骤:
1.创建实例方法类和类中的方法,返回实现类。
2.创建application-context.xml,定义bean在里面写id和class,在定义一个bean在里面写id,factory-bean=“第一个bean的id名”、factory-method=“方法名”
3.在测试类中调用ClassPathXmlApplicationContext加载spring配置文件,之后使用getBean获取bean,在调用方法即可。
-
-
-
5.5spring的依赖注入
-
DI依赖注入:就是将一个容器设置到另一个容器内部。
-
依赖注入的方式:
-
set注入:
在类中创建setxxx方法。
在bean双标签中写property属性标签,设置name属性(值:setxxx的set去掉)、ref属性(定义的另一个bean【即需要注入的那个容器】)
【set注入简便方式:p命名空间注入】:1.在xml文件中赋值第一行加:p。2.直接在被注入的那个bean标签中书写属性p:需要注入的bean的id名-ref=”需要注入的bean的id名“。
-
构造注入:
在类中创建构造方法(空参、有参构造)
在bean双标签中写constructor-arg标签,在该标签中写name=”参数名“、ref=”第一个bean的唯一标识名“。
-
-
依赖注入的三种数据类型:
-
普通数据类型
普通数据类型注入时,使用property标签,在里面写name=”属性名“、value=”属性值“。
引用数据类型
-
集合数据类型
1.list
在xml文件中的bean标签里写property标签,在property标签里写list标签,在list标签里面写value标签【表示list里面的多个值】
...
2.map
在xml文件中的bean标签中写map标签,在map标签里面写porperty里面再写entry标签,entry标签写属性key=”自定义key“,value-ref=”bean标签的id“
##### 3.properties 在xml文件中的bean标签中写property标签,在property标签中写name=“properties”,然后在property标签中写props标签,在props标签中写prop,在prop标签中写属性key=“自定义名称”,在标签体间写值即可
111
-
-
6.spring引入其他配置文件(分模块开发)
spring配置内容非常多时,导致spring配置繁杂体积过大,所以要拆分到不同的配置文件中,而spring主配置文件通过import标签进行加载。
7.spring相关的api
ApplicationContext的实现类
1.ClassPathXmlApplicationContext:从类的根路径下加载配置文件推荐使用
2.FileSystemXmlApplicationContext:从磁盘路径加载配置文件
3.AnnotationConfigApplicationContext:使用注解配置容器对象时,需要使用此类在创建spring容器,它用 来读取注解。
getBean方法
1.传入字符串参数(即传入xml文件中的bean的id)来获取bean
2.传入字节码对象类型(传入接口类的class文件)
注:两种方式的区别:第一种允许xml中的bean的class类重复,因为它是通过id获取的
第二种不允许xml中的bean重复,因为它通过类的字节码获取,而bean的class写的是 接口的实现类。
8.数据源配置
在测试类中读取配置文件properties:
ResourceBundle.getBundle("配置文件名");
在xml文件中加载配置文件properties:
引入Spring的命名空间context,之后使用下面一句代码即可:
最后在需要替换的地方使用${键名}替换即可。
9.spring的注解开发
注解开发主要就是为了简化xml文件的配置繁琐的问题。
原始注解
注解 | 说明 |
---|---|
@Component | 使用在类上用于实例化bean |
@Controller | 使用在web层用于实例化bean |
@Service | 使用在service层用于实例化bean |
@Repository | 用在dao层用于实例化bean |
@Autowired | 用在字段上用于更具类型注入 |
@Qualifier | 结合@Autowired一起使用用于根据名称进行依赖注入 |
@Resource | 相当于@Autowired和@Qualifier,按名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注bean的作用范围 |
@PostConstruct | 使用在方法上标注该方法是bean的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是bean的销毁方法 |
使用组件扫描注意事项
注:使用注解开发时,需要进行在spring配置文件中配置组件扫描,作用是指定哪个包及其子包下的bean需要进行组件扫描以便识别使用注解配置的类、方法和字段。
如果没有加这句注解扫描的配置,就会报NoSuchBeanDefinationException
配置组件扫描代码:
注解的依赖注入(按名称注入)
方式1:@Resource(name="xml文件的bean的id")
方式2:@Autowired @Qualifier("xml文件的bean的id")
@Value的使用
在xml文件中,加载properties配置文件
@value(${jdbc.driver})
private String driver;
10.spring的新注解
使用老注解并不能替换所有的xml配置文件,因此需要新注解。
非自定义的bean的配置
-
加载properties文件的配置:
组件扫描配置:
-
引入其他文件
以上四条的xml配置的替换注解
注解 | 说明 |
---|---|
@Configuration | 用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解 |
@ComponentScan | 用于指定spring在初始化时要扫描的包。作用和在spring的xml配置文件中的context:component-scan相同。 |
@Bean | 使用在方法上标识该方法的返回值存储到spring容器中 |
@PropertySource | 用于加载.properties文件中的配置 |
@Import | 用于导入其他配置类 |
使用注解零配置时,测试时需要使用AnnotationConfigApplicationContext(配置类的字节码文件)进行获取配置,之后使用getBean(接口类的字节码文件)进行获取bean即可。
11.spring集成junit
思考:为什么spring要集成junit呢?因为spring不集成junit的话,就需要在测试类中写两句话(读取xml配置文件或者配置类,获取springBean对象)来获取容器。如果不写就会报空指针异常。
junit负责创建spring容器,但是需要将配置文件的名称告诉他,将进行测试的bean直接在测试类中注入即可。
spring集成junit步骤
1.导入spring-test
2.使用@Runwith(SpringJunit4ClassRunner.class)注解替换原有的运行期
3.使用@ContextConfiguration指定配置文件(”classpath:文件名“)或配置类(classes={配置类字节码文件})
4.使用@Autowired注入测试对象
5.创建测试方法进行测试
12.spring的aop
什么是AOP(Aspect Oriented Programming)的缩写,通过预编译方式和动态期动态代理实现程序功能的统一维护的一种技术。
aop作用和优势:在程序运行期间,在不修改源码的情况下对方法进行增强。
aop优势:减少重复代码,提高开发效率,并便于维护
AOP底层就是spring动态代理实现的,动态代理包括Cglib(基于父类动态代理技术)和JDKproxy(基于接口动态代理技术)
基于JDKproxy的底层核心代码
public class ProxyTest {
public static void main(String[] args) {
final Target target = new Target();//创建目标类实现类
final Advice advice = new Advice();//创建增强类实现类
//返回父类接口,JDKproxy的代理类与目标类实现同一个接口
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.afterRunning();//后置增强
return invoke;
}
}
);
proxyInstance.save();
}
}
基于cglib的底层核心代码
public class ProxyTest {
public static void main(final String[] args) {
final Target target = new Target();
final Advice advice = new Advice();
//创建增强
Enhancer enhancer = new Enhancer();
//设置父类(目标类)
enhancer.setSuperclass(Target.class);
//设置增强器
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
advice.before();
Object invoke = method.invoke(target, args);
advice.afterRunning();
return invoke;
}
});
//创建代理对象
Target proxy = (Target) enhancer.create();
proxy.save();
}
}
aop的相关术语的概念
Target | 代理的目标对象 |
---|---|
Proxy | 一个类被AOP织入增强后产生的代理类对象 |
joinpoint | 连接点就是目标对象可以被增强的方法(多个方法) |
pointcut | 切入点就是目标方法被增强的方法 |
advice | 通知/增强就是对目标方法增加的内容 |
aspect | 切面:就是切点+通知 |
weaving | 织入:就是把增强应用到目标对象来创建代理对象的过程 |
基于xml的aop开发
快速入门
1.导入aop坐标【aspectjweaver】
2.创建目标类和目标接口(内部有切点【即方法】)
3.创建切面类(内部有增强方法)
4.将目标类和切面类的创建权交给spring
5.在spring的xml配置文件中配置织入关系(声明目标类bean和通知类bean,引入aop命名空间然后织入)
6.测试
切点表达式
语法:execution(【修饰符】 返回值类型 包名.类名.方法名)
*代表任意
..代表任意参数个数,任意个数
切点表达式的抽取
声明切点表达式
使用切点表达式
通知类型
名称 | 标签 |
---|---|
前置通知 | |
后置通知 | |
环绕通知(前置加后置) | |
异常抛出通知(有异常就通知) | |
最终通知(不管怎样都会通知) |
环绕通知方法声明时需要传递一个参数(pjp):
public Object around(ProceedingJoinPoint pjp){
Object proceed=pjp.proceed();
return proceed;
}
基于aop的注解开发
快速入门
开发步骤:
1.创建目标接口和目标类
2.创建切面类(内有增强方法) 加@Aspect 在增强方法中使用@通知类型(“切点表达式”)
3.将目标类和切面类的创建权交给spring 加@Component
4.在切面类中使用织入关系
5.在配置文件中开启组件扫描和自动代理
用注解方式时,开启aop自动代理两种方式:1.在配置类中加@EnableApectJAutoProxy
2.需要创建一个xml文件,声明aop命名空间
6.测试
注解的五种通知方式
除了异常通知不太一样其他标识基本相同:异常通知@AfterThrowing
抽取切点表达式
//定义切点表达式
@Pointcut("切点表达式")
public void 方法名(){}
//切点表达式使用
@通知类型("类名.定义的方法名")
13.spring jdbcTemplate基本使用
开发步骤
1.导入spring-jdbc(操作mysql)和spring-tx(管理事务)
2.创建数据库表和实体
3.创建jdbcTemplate对象
4.执行数据库操作
不使用spring时,耦合性较强
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUser("root");
dataSource.setPassword("password");
System.out.println(dataSource);
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
使用spring时,可以解耦将容器的创建权交给spring
//c3p0连接池数据源,配置连接
//引用jdbc模板,注入ds
//在测试类中注入jdbcTemplate,可以从spring容器中获取
@Autowaired
JDBCTemplate jdbctemplate;
//配置运行时环境
@RunWith(“SpringJUnit4ClassRunner.class”)
//加载配置
@ContextConfiguration(“classpath:配置文件”)
JDBCTemplate的增删改查相关的api及参数
增删改基本类似
//返回值为一个整形数,里面的参数arg就是来替换sql语句的?
jdbcTemplate.insert|delete|update;
查询语句的API
//查询所有的信息返回List集合
jdbcTemplate.query(sql,new BeanPropertyRowMapper<实体类>(实体类字节码文件));
//查询单条数据
//queryForObject里面的参数为:SQL语句、封装实体、替换参数
User user = jdbcTemplate.queryForObject("select * from user where id=?", new BeanPropertyRowMapper
//查询总记录数
Integer i = jdbcTemplate.queryForObject("select count(1) from user", Integer.class);
14.声明式事务
什么是编程式?就是自己使用java的api写代码。
什么式声明式?就是以配置的方式进行配置。
编程式事务控制相关的对象
1.平台事务管理器
platformTransactionManager接口是spring的事务管理器,它里面提供了我们常用的操作事务的方法。
方法 | 说明 |
---|---|
TransactionStatus getTransaction(TransactionDefination defination) | 获取事务的状态信息 |
void commit(TransactionStatus status) | 提交事务 |
void rollback(TransactionStatus status) | 回滚事务 |
2.TransactionDefinition是事务的定义信息对象。
方法 | 说明 |
---|---|
int getInsolationLevel() | 获取隔离级别 |
int getPropogationBehavior() | 获取传播行为 |
int getTimeout() | 获取超时时间 |
Boolean idReadyOnly() | 是否只读 |
(1)事务隔离级别
设置事务隔离级别可以解决脏读、不可重复读、幻(虚)读的问题
ISOLATION_DEFAULT
ISOLATION_UNCOMMIT(都不能解决)
ISOLATION_COMMIT(解决脏读)
ISOLATION_REPEATABLE-READ(可重复读事务:可以解决不可重复读)
ISOLATION_SERIALIZABLE(解决幻读,效率超低相当于锁表一般不用)
(2)事务传播行为
REQUIRED:如果当前没有事务,就创建新事务。如果有事务,加入到该事务中。
SUPPORTS:如果当前有事务,就使用当前事务,如果当前没事务,就以非事务方式运行。
MANDATORY:如果当前有事务,就使用当前事务。如果当前没事务,就抛出异常。
REQUIRS_NEW:新建事务,如果当前存在事务,就把当前事务挂起。
NOT_SUPPORTED:以非事务的方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER:以非事务的方式运行,如果当前存在事务,就抛出异常。
NESTED:如果当前存在事务,就嵌套在事务中执行。如果没有事务,则执行REQUIRED类似的操作。
超时时间:默认值为-1,没有超时限制。如果有,以秒为单位进行设置。
是否只读:建议查询时设为只读。
3.TransactionStatus
TransactionStatus接口提供事务的具体的运行状态。
方法 | 说明 |
---|---|
boolean hasSavepoint() | 是否存储回滚点 |
boolean isCompleted() | 事务是否完成 |
boolean isNewTransaction() | 是否是新事务 |
boolean isRollback() | 事务是否回滚 |
声明式事务控制【底层使用的是AOP】
什么是声明式事务控制?Spring的声明式事务控制就是采用声明的方式处理事务。【在xml进行配置】
声明式事务控制的优点:1.事务管理不侵入开发的组件【事务管理是系统层面,不是逻辑业务的一部分】
2.在不需要事务时,不需要修改源码,只需要删掉配置即可。
事务的xml配置
事务的注解配置
(1)在配置文件中声明数据源事务管理器
(2)在切点方法上面加@Transactional注解在里面配置:隔离级别、传播行为、超时时间、是否只读
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED,timeout = -1,readOnly = false)
(3)在xml文件中配置事务注解扫描