根据B站的狂神说的视频学习时写的笔记
链接https://www.bilibili.com/video/BV1WE411d7Dv
1、Spring
1.简介
Spring : 春天 —>给软件行业带来了春天
2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。
2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。
Rod Johnson 他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。
Spring理念 : 使现有技术更加容易使用. 本身就是一个大杂烩 , 整合现有的技术框架。
官网:https://spring.io/
官方下载: https://repo.spring.io/release/org/springframework/spring/
GitHub: https://github.com/spring-projects/spring-framework
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
2.优点
- Spring是一个开源的免费的框架(容器)!
- Spring是一个轻量级、非入侵式的框架!
- 控制反转(IOC) , 面向切面编程(AOP)【面试重点】
- 支持事物的处理,对框架整合的支持
总结:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!
3.组成
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zjEhjJHW-1591531353830)(C:\Users\42084\AppData\Roaming\Typora\typora-user-images\image-20200605110948557.png)]
4.拓展
- Spring Boot
- 一个快速开发的脚手架
- 基于SpringBoot可以快速的开发单个微服务
- 约定大于配置!
- Spring Cloud
- springCloud是基于SpringBoot实现的
现在大多数公司都在使用SpringBoot进行快速开发
缺点:发展太久之后,违背原来理念!配置十分繁琐,人称:“配置地狱”
2、IOC 理论推导
-
之前,程序是主动创建对象的!控制权在程序员手上!
public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoImpl(); public void getUser() { userDao.getUser(); } }
-
使用set注入以后,程序不在具有主动性,而是变成了被动接受的对象
public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void getUser() { userDao.getUser(); } }
这种细想,从本质上解决了问题,我们程序员不用再去管理对象的创建了。系统的耦合性大大降低。可以更加专注在业务的实现上。这是IOC原型
IOC本质
控制反转loC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。 没有IoC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
3.HelloSpring
- 首先创建一个Java Bean对象
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Hello{" +
"name='" + name + '\'' +
'}';
}
}
- 编写Spring的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!--
普通创建对象
类型 变量名 = new 类型();
现在
id就是变量名
class为类型
property为对象赋值
ref:引用Spring容器中创建好的对象
value:具体的值,一般是基本数据类型
-->
<bean id="hello" class="com.kuang.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
</beans>
- 在测试类中读取
public class MyTest {
public static void main(String[] args) {
// 获取Spring的上下文对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 我们的对象都在Spring中管理
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello);
}
}
4.IOC创建对象的方式
1.无参构造(set注入)
<!--无参构造 通过set注入-->
<bean id="user" class="com.kuang.pojo.User">
<property name="name" value="123"/>
</bean>
2.有参构造(构造器注入)
-
通过index下标赋值
<!-- 有参构造,通过index下标注入 --> <bean id="user2" class="com.kuang.pojo.User"> <constructor-arg index="0" value="解"/> </bean>
-
通过type类型赋值【不建议使用】
<!-- 有参构造,通过type类型注入 --> <bean id="user3" class="com.kuang.pojo.User"> <constructor-arg type="java.lang.String" value="贞"/> </bean>
-
通过name参数名赋值
<!-- 有参构造,通过name参数名注入 --> <bean id="user3" class="com.kuang.pojo.User"> <constructor-arg name="name" value="东"/> </bean>
3.总结
在配置文件加载的时候,容器中管理的对象就已经初始化了!
5.Spring配置
1.alias别名
<bean id="user" class="com.kuang.pojo.User">
<property name="name" value="123"/>
</bean>
<alias name="user" alias="userx"/>
为user起一个别名为userx,此时两个名字都可以用
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
user.show();
User userx = (User) context.getBean("userx");
user.show();
}
2.Bean的配置
id :bean的唯一标识符;
class :bean对象所对应的全限定名:包名+类型
name :为bean设置别名,可以同时取多个别名,多个别名之间可以使用空格,逗号,分号进行分割
<bean id="user" class="com.kuang.pojo.User" name="u u1,user1;user5">
<property name="name" value="123"/>
</bean>
3.import导入
这个import,一般用于团队开发使用,它可以将多个配置文件合并为一个。
<import resource="beans.xml"/>
6.依赖注入
1.构造器注入
之前的有参构造就是构造器注入
2.通过Set注入【重点】
-
依赖注入:Set出入!
-
依赖:bean对象的创建以来容器
-
注入:bean对象中的所有属性,由容器来注入
-
【环境搭建】
-
复杂类型
public class Address { private String addres; public String getAddres() { return addres; } public void setAddres(String addres) { this.addres = addres; } }
-
真实类型
public class Student { private String name; private Address address; private String[] book; private List<String> hobbys; private Map<String,String> card; private Set<String> games; private Properties info; private String wife; //后半部分为set和get方法与toString方法 }
-
bean.xml
<bean id="address" class="com.kuang.pojo.Address"> <property name="addres" value="西安"/> </bean> <bean id="student" class="com.kuang.pojo.Student"> <!-- 普通类型注入,value--> <property name="name" value="东"/> <!-- Bean注入,ref--> <property name="address" ref="address"/> <!-- 数组注入,array--> <property name="book"> <array> <value>红楼梦</value> <value>西游记</value> <value>水浒传</value> <value>三国演义</value> </array> </property> <!-- List注入,list--> <property name="hobbys"> <list> <value>听歌</value> <value>敲代码</value> <value>打游戏</value> </list> </property> <!-- Map注入,map--> <property name="card"> <map> <entry key="身份证" value="123123123123123123"/> <entry key="手机号" value="15778965441"/> </map> </property> <!-- Set注入,set--> <property name="games"> <set> <value>LOL</value> <value>DNF</value> <value>CF</value> </set> </property> <!-- props注入,props--> <property name="info"> <props> <prop key="学号">17</prop> <prop key="性别">男</prop> <prop key="姓名">小明</prop> </props> </property> <!-- null注入,null--> <!-- <property name="wife" value=""/>--> <property name="wife"> <null/> </property> </bean>
-
测试
3.拓展方式注入
-
p命名空间注入(对应set注入)
-
收钱确保对象有无参构造方法
public User() { }java
-
加入p命名空间
xmlns:p="http://www.springframework.org/schema/p"
-
p注入
<!--p命名空间注入--> <bean id="user" class="com.kuang.pojo.User" p:name="东" p:age="18"/>
-
-
c命名空间注入(对应构造器注入)
-
首先确保对象有含参构造方法
public User(String name, int age) { this.name = name; this.age = age; }
-
加入c命名空间
xmlns:c="http://www.springframework.org/schema/c"
-
c注入
<!--c命名空间注入,通过构造器注入:construct-args--> <bean id="user2" class="com.kuang.pojo.User" c:name="西" c:age="18"/>
-
4.Bean作用域
-
单例模式(默认)
<bean id="user" class="com.kuang.pojo.User" scope="singleton" p:name="东" p:age="18"/>
@Test public void isuser(){ ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml"); User user1 = context.getBean("user", User.class); User user2 = context.getBean("user", User.class); System.out.println(user1==user2); //true }
-
原型模式
<bean id="user" class="com.kuang.pojo.User" scope="prototype" p:name="东" p:age="18"/>
@Test public void isuser(){ ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml"); User user1 = context.getBean("user", User.class); User user2 = context.getBean("user", User.class); System.out.println(user1==user2); //false }
-
其余的 request、session、application 这些只能在web开发中使用
7.Bean的自动装配
-
自动装配是Spring满足Bean依赖一种方式
-
Spring会在上下文中自动寻找,并自动给Bean装备属性
在Spring中有三种装配的方式
1.在xml中显示的配置
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="person" class="com.kuang.pojo.Person">
<property name="name" value="东"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>
2.在java中显示配置
-
ByName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid
<bean id="cat" class="com.kuang.pojo.Cat"/> <bean id="dog" class="com.kuang.pojo.Dog"/> <bean id="person" class="com.kuang.pojo.Person" autowire="byName"> <property name="name" value="东"/> </bean>
-
ByType:会自动在容器上下文中查找,和自己对象属性类型相同的bean
<bean id="cat" class="com.kuang.pojo.Cat"/> <bean id="dog111" class="com.kuang.pojo.Dog"/> <bean id="person" class="com.kuang.pojo.Person" autowire="byType"> <property name="name" value="东"/> </bean>
如果此时相同类型存在多个就会报错
<bean id="cat" class="com.kuang.pojo.Cat"/> <bean id="dog111" class="com.kuang.pojo.Dog"/> <bean id="dog222" class="com.kuang.pojo.Dog"/> <bean id="person" class="com.kuang.pojo.Person" autowire="byType"> <property name="name" value="东"/> </bean>
小结:
- ByName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
- ByType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致
3.隐式的自动装配Bean(重要)
使用注解实现自动装配
-
导入约束。context(3,6,7行)
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> </beans>
-
开启注解的支持
<context:annotation-config/>
-
使用注解
-
@Autowired(原理先执行ByName后执行ByType,注解也可以加到set方法上,可以省略set方法)
@Autowired private Cat cat; @Autowired private Dog dog; private String name;
科普:
@Nullable //可以使一个属性为null也不会报错 @Autowired(required = false)//与@Nullable相似,当属性为null也不会报错
-
@Qualifier(value = “beanid”)(当我们使用@Autowired无法实现自动装配时,我们可以利用@Qualifier配合@Autowired使用指定一个beanid)
@Autowired @Qualifier(value = "cat") private Cat cat; @Autowired @Qualifier(value = "dog") private Dog dog; private String name;
-
@Resource(Java的原生注解)
可以通过name指定一个Bean对象
@Resource(name = "cat") private Cat cat; @Resource private Dog dog;
-
小结:@Resource和@Autowired的区别
- 都是用来自动装配的,都可以放在属性字段上。
- @Autowried:注入首先根据ByType注入,当类型大于1时在根据byName注入。
- @Resource:默认按照ByName自动注入,如果找不到name则通过ByType实现。
8.使用注解开发
在使用注解开发,必须保证aop的包导入了
使用注解还需要导入context约束,支持注解的配置
<?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: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/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描指定包下的注解,这个包下的注解就会生效-->
<context:component-scan base-package="com.kuang.pojo"/>
<!-- 开启注解支持-->
<context:annotation-config/>
</beans>
-
bean
@Component public class User { @Value("东东") public String name; }
@Component :组件,放在类上,说明这个类被Spring管理了,就是bean
-
属性如何注入
@Component public class User { @Value("东东") public String name; }
使用value注入值,同时可以把@Value放到set上
-
衍生注解
@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!
-
dao【@Repository】
@Repository public class UserDao { }
-
service【@Service】
@Service public class UserService { }
-
controller【@Controller】
@Controller public class UserController { }
-
-
自动装配
-
作用域
-
单实例作用域
@Repository @Scope("singletion") public class UserDao { }
-
多实例作用域
@Repository @Scope("prototype") public class UserDao { }
-
-
小结
xml与注解:
- xml更加万能,适用于任何场合!维护简单方便
- 注解具有局限性,维护起来比较复杂
9.使用Java的方式配置Spring
纯Java配置Spring
JavaConfig时Spring的一个子项目,在Spring4之后,它成为了一个核心功能。
-
实体类
@Component public class User { private String name; public String getName() { return name; } @Value("xzd123") public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; } }
-
配置文件
@Configuration//相当于一个beans.xml文件 @ComponentScan("com.kuang")//扫描注解 @Import(MyConfig2.class)//导入其他的配置文件 public class MyConfig { //相当于bean标签,方法名相当于id,返回值相当于class @Bean public User MyUser(){ //返回要注入到bean的对象 return new User(); } }
-
测试
public static void main(String[] args) { //使用AnnotationConfigApplicationContext读取config的class文件 ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); //这里的beanid为config文件中@Bean的方法名 User myUser = context.getBean("MyUser", User.class); System.out.println(myUser); }
10.代理模式
这就是SpringAOP的底层
代理模式的分类:
1.静态代理
角色分析:
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后会进行一些附属操作
- 客户:访问代理对象的人
代码步骤:
-
接口
public interface Rent { public void rent(); }
-
真是角色
public class Host implements Rent{ public void rent() { System.out.println("房东出租房子"); } }
-
代理角色
public class Proxy implements Rent{ private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } public void rent() { host.rent(); seeHouse(); hetong(); fare(); } public void seeHouse(){ System.out.println("中介带你看房"); } public void hetong(){ System.out.println("签合同"); } public void fare(){ System.out.println("收钱"); } }
-
客户端访问代理角色
public class Me { public static void main(String[] args) { Host host = new Host(); Proxy proxy = new Proxy(host); proxy.rent(); } }
代理模式的好处:
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
- 公共的业务就交给了代理角色!实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理
缺点:
- 一个真实角色就会产生一个代理角色;代码会翻倍开发效率会降低
2.动态代理
- 动态代理和静态代理角色一样
- 动态代理的的代理类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口–JDK动态代理
- 基于类:cglib
- java字节码实现:javassist
需要了解两个类:Proxy:代理,InvocationHandler:调用处理程序
Proxy:
第一个参数:需要该类的类加载器
第二个参数:需要该对象的接口
第三个参数:代理类
Foo f =(Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class<?>[] { Foo.class},handler);
InvocationHandler:需要重写invoke方法
动态代理的好处
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
- 公共的业务就交给了代理角色!实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理
- 一个动态代理类代理的是一个接口,一般对应的是一类业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口
public class ProxyInvovationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到的代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
//动态代理的本质,就是使用反射机制实现!
Object invoke = method.invoke(target, args);
return invoke;
}
public void log(String msg){
System.out.println("执行了"+msg+"方法");
}
}
11.AOP
1.什么是AOP
AOP(Aspect Orient Programming),称为面向切面编程,它作为面向对象(OOP)的一种补充,用于处理系统中分布于各个模板的横切关注点,比如事务管理、日志、缓存等。AOP实现的关键点是AOP框架自动创建的AOP代理,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。静态代理是编译期实现,动态代理是运行期实现,前者拥有更好的性能。Spring AOP的两种代理实现机制,jdk动态代理和cglib动态代理。
2.AOP在Spring中的作用
提供声明式事务;允许用户自定义切面
- 横切关注点:跨越应用程序多个模块的方法和功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如:日志,安全,缓存,事务等等。。
- 切面(Aspect):横切关注点被模块化的特殊对象。他是一个类。
- 通知(Advice):切面必须要完成的工作。他是一个方法。
- 目标(Target):被通知的对象
- 代理(Proxy):向目标对象应用通知之后创建的对象
- 切入点(PointCut):切面通知执行的“地点”的定义
- 连接点(JoinPoint):与切入点匹配的执行点
Spring AOP中,通过Advice定义横切逻辑,Spring中支持5中类型的Advice
-
前置通知
方法前:MethodBeforeAdvice
-
后置通知
方法后:AfterReturningAdvice
-
环绕通知
方法前后:MethodInterceptor
-
异常抛出通知
方法抛出异常:ThrowsAdvice
-
引介通知
类中增加新的方法属性:IntroductionInterceptor
3.使用Spring AOP
要使用Spring AOP首先要导入jar包
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
4.使用原生Spring API接口实现AOP
-
首先要有被代理业务的接口和实现类
public interface UserService { void add(); void delete(); void update(); void query(); }
public class UserServiceImpl implements UserService { public void add() { System.out.println("tianjia"); } public void delete() { System.out.println("shanchu"); } public void update() { System.out.println("xiugai"); } public void query() { System.out.println("chaxun"); } }
-
定义通知的类(通过实现不同的接口,定义不同的通知类)
public class Log implements MethodBeforeAdvice { //method:要执行目标对象的方法 //objects:参数 //target:目标对象 public void before(Method method, Object[] objects, Object target) throws Throwable { System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了"); } }
public class AfterLog implements AfterReturningAdvice { //returnValue:返回的结果 //method:执行的方法 public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("执行了"+method.getName()+"返回结果为:"+returnValue); } }
-
配置Spring配置文件,支持AOP
<!-- 配置Bean--> <bean id="userService" class="com.kuang.service.UserServiceImpl"/> <bean id="log" class="com.kuang.log.Log"/> <bean id="after" class="com.kuang.log.AfterLog"/> <!-- 方式一:使用原生Spring API接口--> <!-- 配置aop:需要导入aop约束--> <aop:config> <!-- 切入点:expression:表达式,execution:(要执行的位置) --> <aop:pointcut id="ponintcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/> <!--执行环绕增加 --> <aop:advisor advice-ref="log" pointcut-ref="ponintcut"/> <aop:advisor advice-ref="after" pointcut-ref="ponintcut"/> </aop:config>
-
测试
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); //动态代理的是接口:注意点 UserService userService = context.getBean("userService", UserService.class); userService.query(); }
5.使用自定义类实现AOP【切面定义】
-
自定义一个类,在其中写入要执行的通知内容
public class DiyPointCut { public void before(){ System.out.println("=====方法执行前====="); } public void after(){ System.out.println("=====方法执行后====="); } }
-
配置Spring配置文件
<!-- 配置Bean--> <bean id="userService" class="com.kuang.service.UserServiceImpl"/> <bean id="log" class="com.kuang.log.Log"/> <bean id="after" class="com.kuang.log.AfterLog"/> <!--方式二:自定义类 --> <bean id="diy" class="com.kuang.diy.DiyPointCut"/> <aop:config> <!-- 自定义切面,ref要引用的类 --> <aop:aspect ref="diy"> <!-- 切入点--> <aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/> <!--配置通知的类型和要在哪个切入点执行哪个方法--> <aop:before method="before" pointcut-ref="point"/> <aop:after method="after" pointcut-ref="point"/> </aop:aspect> </aop:config>
-
测试
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); //动态代理的是接口:注意点 UserService userService = context.getBean("userService", UserService.class); userService.query(); }
6.使用注解实现
-
定义一个类,并未它添加注解
@Aspect//标注这个类是一个切面 public class AnnotationPointCut { @Before("execution(* com.kuang.service.*.*(..))") public void before(){ System.out.println("======方法执行前======"); } @After("execution(* com.kuang.service.*.*(..))") public void after(){ System.out.println("---方法执行后---"); } // 在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点 @Around("execution(* com.kuang.service.*.*(..))") public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("环绕前"); //获得签名 Signature signature = jp.getSignature(); System.out.println(signature); //执行方法 Object proceed = jp.proceed(); System.out.println("环绕后"); }
-
在配置文件中配置
<!-- 配置Bean--> <bean id="userService" class="com.kuang.service.UserServiceImpl"/> <bean id="log" class="com.kuang.log.Log"/> <bean id="after" class="com.kuang.log.AfterLog"/> <!-- 方式三:使用注解 --> <bean id="anno" class="com.kuang.diy.AnnotationPointCut"/> <!-- 开启注解支持! JDK(默认 proxy-target-class="false" ) cglib(proxy-target-class="true")--> <aop:aspectj-autoproxy proxy-target-class="true"/>
12.整合Mybatis
步骤:
- 导入jar包
- junit
- mybatis
- 数据库驱动
- spring相关的
- aop织入
- mybatis-spring【new】
- 编写配置文件
- 测试
回忆Mybatis
- 编写实体类
- 编写核心配置文件
- 编写接口和Mapper.xml
- 测试
Mybatis-Spring整合
-
编写数据源
-
SqlSessionFactory
<!--DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=gbk&serverTimezone=GMT"/> <property name="username" value="root"/> <property name="password" value="password"/> </bean> <!--SqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 绑定Mybatis--> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:com/kuang/dao/*.xml"/> </bean>
-
SqlSessionTemplate 或者 SqlSessionDaoSupport
- 使用SqlSessionTemplat
<!--SqlSessionTemplate:就是我们使用的SqlSession --> <bean id="SqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!--只能用constructor-arg 注入,因为它没有set方法 --> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean>
- 使用SqlSessionDaoSupport(不需要bean对象,只需要配置接口实现类和注入Spring)
-
需要给接口加实现类
- SqlSessionTemplate 的接口实现类
public class MajorMapperImpl implements MajorMapper { private SqlSessionTemplate sqlSession; public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } public List<Major> selectMajor() { MajorMapper mapper = sqlSession.getMapper(MajorMapper.class); return mapper.selectMajor(); } }
- SqlSessionDaoSupport的接口实现类
//实现接口并且继承SqlSessionDaoSupport public class MajorMapperImpl2 extends SqlSessionDaoSupport implements MajorMapper { public List<Major> selectMajor() { // SqlSession sqlSession = getSqlSession(); // MajorMapper mapper = sqlSession.getMapper(MajorMapper.class); // List<Major> majors = mapper.selectMajor(); return getSqlSession().getMapper(MajorMapper.class).selectMajor(); } }
-
将自己写的实现类注入到Spring中测试
- 使用SqlSessionTemplate
<bean id="majorMapper" class="com.kuang.dao.MajorMapperImpl"> <property name="sqlSession" ref="SqlSession"/> </bean>
- 使用SqlSessionDaoSupport(需要一个sqlSessionFactory参数)
<bean id="majorMapper2" class="com.kuang.dao.MajorMapperImpl2"> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean>
-
测试
@Test public void selectMajor() throws IOException { ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml"); MajorMapper majorMapper = context.getBean("majorMapper", MajorMapper.class); List<Major> majors = majorMapper.selectMajor(); for (Major major : majors) { System.out.println(major); } }
13.声明式事务
1.回顾事务
- 要么都成功,要么都失败!
- 事务在项目开发中,非常重要,涉及到数据的一致性问题
- 确保完整性和一致性
2.事务的ACID原则
- 原则性
- 一致性
- 隔离性
- 多个事务可能操作同一个资源,防止数据毁坏
- 持久性
- 事务一旦提交,无论系统发生什么问题,结果都不会被影响,被持久化的写到存储器中!
3.spring中的事务管理
-
声明式事务:AOP
-
首先要配置声明式事务、
-
配置事务的类(给哪些方法配置事务,配式事物的传播特性)
-
AOP配置一个切入点,使配置事务的类切入
<!-- 配置声明式事务 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <constructor-arg ref="dataSource" /> </bean> <!-- 结合AOP实现事务的植入 --> <!--配置事务的类--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--给那些方法配置事务--> <!--配置事务的传播特性 propagation:事务传播特性,常用REQUIRED(默认) NESTTED--> <tx:attributes> <tx:method name="add" propagation="REQUIRED"/> <tx:method name="delete" propagation="REQUIRED"/> <tx:method name="update" propagation="REQUIRED"/> <!--quert 只读--> <tx:method name="query" read-only="true"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--配置切入点切入--> <aop:config> <aop:pointcut id="txPointCut" expression="execution(* com.kuang.dao.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config>
-
整性和一致性
2.事务的ACID原则
- 原则性
- 一致性
- 隔离性
- 多个事务可能操作同一个资源,防止数据毁坏
- 持久性
- 事务一旦提交,无论系统发生什么问题,结果都不会被影响,被持久化的写到存储器中!
3.spring中的事务管理
-
声明式事务:AOP
-
首先要配置声明式事务、
-
配置事务的类(给哪些方法配置事务,配式事物的传播特性)
-
AOP配置一个切入点,使配置事务的类切入
<!-- 配置声明式事务 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <constructor-arg ref="dataSource" /> </bean> <!-- 结合AOP实现事务的植入 --> <!--配置事务的类--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--给那些方法配置事务--> <!--配置事务的传播特性 propagation:事务传播特性,常用REQUIRED(默认) NESTTED--> <tx:attributes> <tx:method name="add" propagation="REQUIRED"/> <tx:method name="delete" propagation="REQUIRED"/> <tx:method name="update" propagation="REQUIRED"/> <!--quert 只读--> <tx:method name="query" read-only="true"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--配置切入点切入--> <aop:config> <aop:pointcut id="txPointCut" expression="execution(* com.kuang.dao.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config>
-
-
编程式事务:需要使用try catch实现当事务失败时使事务回滚()