Spring
简介
spring是分层的javaSE/EE应用full-stack轻量级开源框架,以Ioc(Inverse Of Control :反转控制)和AOP(Aspect OrientedProgramming:面向切面编程)为内核。
Spring优势
Spring的体系结构
Spring的快速入门
在以往学的的开发中,我们都是通过Service层来调用dao层的方法
现在使用spring框架之后 ,spring 的开发步骤
1.导入spring坐标
2.编写userdao接口和userdao的实现
3.创建一个xml配置文件(spring核心配置文件)
4.把userdaoimpl配置到xml里面 id标识=userdaoimp的全限定类名
<bean id="userDao" class="com.ry.dao.impl.UserDao"></bean>
5.通过spring客户端的getBean(id表示)方法来返回指定的对象(使用spring的api获得bean实例)
Spring配置文件
Bean标签基本配置
用于配置对象交由Spring来创建
默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功
基本属性:
- id:Bean实例在Spring容器中的唯一标识
- class:Bean的全限定名称
Bean标签范围配置
scope:指对象的作用范围,取值如下:
singleton:在容器当中,存在这个对象只有一个,地址值唯一
com.ry.dao.impl.UserDao@158d2680
com.ry.dao.impl.UserDao@158d2680
prototype:容器中有多个这个对象,每次都会重新创建一个,地址值不同
com.ry.dao.impl.UserDao@1d2adfbe
com.ry.dao.impl.UserDao@36902638
Bean生命周期配置
Bean实例化的三种方式
最常用的是无参构造
Bean的依赖注入
依赖注入:它是Spring框架核心IOC的具体实现
Bean的依赖注入方式:
怎么将UserDao注入到UserService内部呢
构造方法
set方法
set方法注入
//在service的实现类当中添加一个set方法
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao=userDao;
}
优化: p:标签注入步骤
1.重新开辟一个命名空间
2.复制这个 xmlns="http://www.springframework.org/schema/beans"
3.改成这样的 xmlns:p="http://www.springframework.org/schema/p"即可
4.然后在后面添加一个p:userDao-ref="userDao"即可
<bean id="userService" class="com.ry.services.impl.UserServiceImpl"
p:userDao-ref="userDao"></bean>
配置文件中
有参构造方法注入
//UserService的实现类中提供一个无参构造和一个有参构造
public UserServiceImpl() {
}
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
配置文件中
Bean的依赖注入数据类型
引入其他配置文件(分模块开发)
知识要点
Spring相关API
ApplicationContext的继承体系
ApplicationContext的实现类
getBean()方法使用
知识要点
Spring配置数据源
数据源(连接池)的作用
- 数据源是提高程序性能才出现的
- 事先实例化数据源,初始化部分连接资源
- 使用连接资源时从数据源中获取
- 使用完毕后将连接资源归还给数据源
常见的数据源:DBCP,C3P0,Boncp,Druid等
抽取jdbc配置文件
步骤:
1.引入坐标
2.创建并且配置jdbc.properties配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///test
jdbc.username=root
jdbc.password=root
3.创建并配置spring核心配置文件
<!--加载外部的properties文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
4.调用
创建ClassPathXmlApplicationContext对象
ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
使用它的getBean方法,参数传递 bean的id.class,获取数据源
5.调用数据源的getconnection方法获取连接
Spring注解开发
Spring原始注解
使用步骤:
1.在对应的需要创建bean的类上面加注解【@Component("userDao")】
如果是web层:则使用@Controller注解,
如果是Service层,则使用@Service注解,
如果是dao层,则使用@Repository,
以上三种注解与@Component("userDao")功能一致,但是可读性更强
在需要注入的上面加@Autowired和@Qualifier("userDao")
如果使用注解的方式,则不用创建set方法,它会通过反射去重新赋值,下面一样可以用
当根据数据类型从spring容器中匹配时,@Qualifier注解可以省略
2.测试发现问题nosuchbean的错误,则需要在applicationContext.xml中配置组件扫描
<!--配置组件扫描-->
<context:component-scan base-package="com.ry"/>
标红的需重点掌握
Spring新注解
使用原始注解还不能完全替代xml配置文件,还需要使用注解替代的配置如下:
新注解
利用新注解进行全注解开发
@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("dataSouce") //Spring会将当前方法的返回值以指定名称存储到Spring当中
public DataSource getDataSource() {
DruidDataSource dataSouce = new DruidDataSource();
dataSouce.setDriverClassName(driver);
dataSouce.setUrl(url);
dataSouce.setUsername(username);
dataSouce.setPassword(password);
return dataSouce;
}
}
@Configuration //标志该类是Spring的核心配置类
@ComponentScan("com.ry") //配置组件扫描
@Import(DataSourceConfiguration.class)//加载其它配置文件
public class SpringConfiguration {
}
//调用
ApplicationContext app=new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = (UserService) app.getBean("userService");
userService.save();
Spring集成Junit
解决思路
集成步骤
//使用SpringJUnit4ClassRunner.class内核来帮助进行测试
@RunWith(SpringJUnit4ClassRunner.class)
//@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 {
userService.save();
System.out.println(dataSource.getConnection());
}
}
SpringAop
什么是Aop
Aop(Aspect OrientedProgramming)意思为面向切面编程,
是通过预编译的方式和运行期动态代理实现程序功能的同意维护的一种技术
同时在增强功能的同时是松耦合的
一般情况下,目标方法+增强方法统一成为切面
Aop的作用及其优势
- 作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
- 优势:减少代码重复。提高开发效率,便于后期维护
Aop的底层实现
Aop的动态代理
常用的动态代理技术
- JDK代理:基于接口的动态代理对象
- cglib代理:基于父类的到动态代理技术
JDK的动态代理
//获得增强对象
Advice advice=new Advice();
//返回值就是动态生成的代理对象
TargetInterface proxy= (TargetInterface) Proxy.newProxyInstance(
Target.class.getClassLoader(), //目标对象的类加载器
Target.class.getInterfaces(),//目标对象相同的接口字节码对象数组
new InvocationHandler() {
//调用代理对象的任何方法,实质执行的都是invoke方法
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//前置增强
advice.vefore();
//执行目标方法
Object invoke = method.invoke(new Target(), args);//执行目标方法
//后置增强
advice.after();
return invoke;
}
});
//调用代理对象的方法
proxy.save();
}
cglib动态代理(了解)
//获得增强对象
final Advice advice=new Advice();
//获得目标对象
final Target target = new Target();
//返回值 就是动态生成的代理对象 基于cglib
//1.创建增强器
Enhancer enhancer=new Enhancer();
//2.设置父类(目标)
enhancer.setSuperclass(Target.class);
//3.设置回调
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//执行前置
advice.vefore();
//执行目标
Object invoke = method.invoke(target, args);
//执行后置
advice.after();
return invoke;
}
});
//4.创建代理对象
Target proxy = (Target) enhancer.create();
proxy.save();
}
Aop相关概念
1.(JoinPint)连接点:可以被增强的方法叫连接点
2.(Pintcut)切入点又称切点(属于连接点中的一部分)
例子:我们都是公民,都有机会成为人大代表,但是我们没有成为人大代表前就是连接点,
而当我们成为人大代表后,就是成为了切点。
3.(Advice)增强/通知:将目标方法拦截到之后,我们要对其增强,但是要对其增强,
必然就有一段增强逻辑,这段增强逻辑必然放到一段方法当中,
这个方法就叫做增强/通知
4.(Aspect)切面:切面=切点+通知
5.(Weaving)织入:把切点和通知结合的过程可以称为一个织入过程(动词含义)
Aop开发明确的事项
1.需要编写的内容
- 编写核心业务代码(目标类的目标方法)
- 编写切面类,切面类中有通知(增强功能方法)
- 在配置文件中配置织入关系,就是将哪些通知和哪些连接点进行结合
2.Aop技术实现的内容
3.Aop底层使用哪种代理方式
在spring中,框架会根据目标类是否实现了接口来决定哪种动态代理的方式
知识要点
Sprin基于XML的Aop开发
快速入门
还要注意启动Aop代理
<aop:aspectj-autoproxy proxy-target-class="true"/>
<aop:aspectj-autoproxy/> 其中<aop:aspectj-autoproxy/>有一个 proxy-target-class属性,
默认为false,表示使用JDK动态代理技术织入增强;
当配置为<aop:aspectj-autoproxy proxy-target-class="true"/>时,
表示使用CGLIB动态代理技术织入增强。不过即使proxy-target-class设置为false,
如果目标类没有声明接口,则Spring将自动使用CGLIB动态代理。
spring的很多功能首要条件就是这些bean都要放在容器当中,spring才能从容器当中拿出来bean进行相应的
操作
applicationContext.xml中将目标类和切面类对象创建权交给spring,并配置织入关系
<!--目标对象-->
<bean id="target" class="com.ry.aop.Target" ></bean>
<!--切面对象-->
<bean id="myAspect" class="com.ry.aop.MyAspect"></bean>
<!--配置织入,告诉spring框架,哪些方法需要进行那些增强(前置增强,后置。。。。)-->
<aop:config>
<!--声明切面,告诉spring这是切面对象-->
<aop:aspect ref="myAspect">
<!--抽取切点表达式-->
<aop:pointcut id="myPointcut" expression="execution(public void com.ry.aop.*.*(..))"/>
<!--切面=切点+通知-->
<!-- <aop:before method="before"pointcut-ref="myPointcut""/>-->
<!-- <aop:after-returning method="after"pointcut-ref="myPointcut""/>-->
<aop:around method="around" pointcut-ref="myPointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>
<aop:after method="after" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
1.切点表达式的写法
execution([修饰符]返回值类型 包名.类名.方法名(参数))
- 访问修饰符可以省略
- 返回值类型,包名,类名可以使用星号*代表任意
- 包名与类名之间一个点.代表当前包下的类,两个点…代表当前包机器子包下的类
- 参数列表可以适应两个点…表示任意个数,任意类型的参数列表
例如 :
2.通知的类型
3.切点表达式的抽取
知识要点
Sprin基于注解的Aop开发
//创建目标接口
public interface TargetInterface {
public void save();
}
---------------------------------------------------------------------------------------
//创建目标类
@Component("target")
public class Target {
public void save() {
// int i=1/0;
System.out.println("save running...");
}
}
//创建切面类
//切面类,里面有增强的方法
@Component("myAspect")
@Aspect //标注当前MyAspect是一个切面类
public class MyAspect {
//配置前置增强
@Before("execution(public void com.ry.anno.*.*(..))")//配置织入关系
public void before(){
System.out.println("前置增强........");
}
public void afterruning(){
System.out.println("后置增强........");
}
//ProceedingJoinPoint:正在执行的连链接点===切点
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("最终增强....");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
>
<!--开启组件扫描-->
<context:component-scan base-package="com.ry.anno"/>
<!--开启aop自动代理-->
<aop:aspectj-autoproxy/>
</beans>
//测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-anno.xml")
public class AnnoTest {
@Autowired
private Target target;
@Test
public void test1(){
target.save();
}
}
1.注解通知的类型
2.切点表达式的抽取
知识要点
JDBCTemplate的基本使用
JDBCTemplate的开发步骤
package com.ry.test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class JdbcTemplateTest {
@Test
//测试spring去产生的jdbctemplate对象
public void test2() throws Exception{
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicatonContext.xml");
JdbcTemplate jdbcTemplate = (JdbcTemplate) app.getBean("jdbcTemplate");
//执行操作
int update = jdbcTemplate.update("insert into account values (?,?)","zhangsan","6000");
System.out.println(update);
}
@Test
//测试spring去产生的jdbctemplate对象
public void test3() throws Exception{
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicatonContext.xml");
JdbcTemplate jdbcTemplate = (JdbcTemplate) app.getBean("jdbcTemplate");
//执行操作
int update = jdbcTemplate.update("delete from account where name = ? ","zhangsan");
System.out.println(update);
}
@Test
//测试jdbctemplate开发步骤
public void test1() throws Exception{
//创建数据源对象
ComboPooledDataSource dataSource=new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///test");
dataSource.setUser("root");
dataSource.setPassword("root");
JdbcTemplate jdbcTemplate=new JdbcTemplate();
//设置数据源对象,知道数据库在哪里
jdbcTemplate.setDataSource(dataSource);
//执行操作
int update = jdbcTemplate.update("insert into account values (?,?)","tom","5000");
System.out.println(update);
}
}
late=new JdbcTemplate();
//设置数据源对象,知道数据库在哪里
jdbcTemplate.setDataSource(dataSource);
//执行操作
int update = jdbcTemplate.update(“insert into account values (?,?)”,“tom”,“5000”);
System.out.println(update);
}
}
[外链图片转存中...(img-32o00jjW-1594790948547)]
## Spring的事务控制
#### 编程式事务控制相关对象
[外链图片转存中...(img-A8q1ajSB-1594790948548)]
[外链图片转存中...(img-k8kyiqoX-1594790948549)]
[外链图片转存中...(img-XWXuPP2B-1594790948550)]
## 声明式事务控制{复习完mysql了之后再回来学}
#### 基于xml的事务控制
Spring的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在spring配置文件中声明式的处理事务来代替代码式(编程式)的处理事务。
**声明事务处理的作用**
[外链图片转存中...(img-kyOJZII9-1594790948551)]