spring是分层的javaSE/EE应用full-stack轻量级开源框架,以Ioc(Inverse Of Control :反转控制)和AOP(Aspect OrientedProgramming:面向切面编程)为内核。
在以往学的的开发中,我们都是通过Service层来调用dao层的方法
现在使用spring框架之后 ,spring 的开发步骤
1.导入spring坐标
2.编写userdao接口和userdao的实现
3.创建一个xml配置文件(spring核心配置文件)
4.把userdaoimpl配置到xml里面 id标识=userdaoimp的全限定类名
5.通过spring客户端的getBean(id表示)方法来返回指定的对象(使用spring的api获得bean实例)
用于配置对象交由Spring来创建
默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功
基本属性:
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
最常用的是无参构造
依赖注入:它是Spring框架核心IOC的具体实现
怎么将UserDao注入到UserService内部呢
构造方法
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"即可
//UserService的实现类中提供一个无参构造和一个有参构造
public UserServiceImpl() {
}
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
常见的数据源:DBCP,C3P0,Boncp,Druid等
步骤:
1.引入坐标
2.创建并且配置jdbc.properties配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///test
jdbc.username=root
jdbc.password=root
3.创建并配置spring核心配置文件
4.调用
创建ClassPathXmlApplicationContext对象
ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
使用它的getBean方法,参数传递 bean的id.class,获取数据源
5.调用数据源的getconnection方法获取连接
使用步骤:
1.在对应的需要创建bean的类上面加注解【@Component("userDao")】
如果是web层:则使用@Controller注解,
如果是Service层,则使用@Service注解,
如果是dao层,则使用@Repository,
以上三种注解与@Component("userDao")功能一致,但是可读性更强
在需要注入的上面加@Autowired和@Qualifier("userDao")
如果使用注解的方式,则不用创建set方法,它会通过反射去重新赋值,下面一样可以用
当根据数据类型从spring容器中匹配时,@Qualifier注解可以省略
2.测试发现问题nosuchbean的错误,则需要在applicationContext.xml中配置组件扫描
使用原始注解还不能完全替代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();
//使用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());
}
}
什么是Aop
Aop(Aspect OrientedProgramming)意思为面向切面编程,
是通过预编译的方式和运行期动态代理实现程序功能的同意维护的一种技术
同时在增强功能的同时是松耦合的
一般情况下,目标方法+增强方法统一成为切面
常用的动态代理技术
//获得增强对象
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();
}
//获得增强对象
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();
}
1.(JoinPint)连接点:可以被增强的方法叫连接点
2.(Pintcut)切入点又称切点(属于连接点中的一部分)
例子:我们都是公民,都有机会成为人大代表,但是我们没有成为人大代表前就是连接点,
而当我们成为人大代表后,就是成为了切点。
3.(Advice)增强/通知:将目标方法拦截到之后,我们要对其增强,但是要对其增强,
必然就有一段增强逻辑,这段增强逻辑必然放到一段方法当中,
这个方法就叫做增强/通知
4.(Aspect)切面:切面=切点+通知
5.(Weaving)织入:把切点和通知结合的过程可以称为一个织入过程(动词含义)
在spring中,框架会根据目标类是否实现了接口来决定哪种动态代理的方式
其中 有一个 proxy-target-class属性,
默认为false,表示使用JDK动态代理技术织入增强;
当配置为 时,
表示使用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>
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut id="myPointcut" expression="execution(public void com.ry.aop.*.*(..))"/>
<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>
execution([修饰符]返回值类型 包名.类名.方法名(参数))
例如 :
//创建目标接口
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("最终增强....");
}
}
<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:aspectj-autoproxy/>
beans>
//测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-anno.xml")
public class AnnoTest {
@Autowired
private Target target;
@Test
public void test1(){
target.save();
}
}
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)]