spring
在b站观看狂神自学一个月,笔记总结
文章目录
一 简介
- Spring框架是一个开放源代码的J2EE应用程序框架,由[Rod Johnson](https://baike.baidu.com/item/Rod Johnson/1423612?fromModule=lemma_inlink)发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。
- Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。
- Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于J2EE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。
- Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。
- 优点:
- 开源免费的框架(容器)
- 轻量级,非入侵式的框架
- 控制反转(IOC)、面向切面编程(AOP)
- 支持事务的处理、对框架整合的支持
二 IOC
-
IOC理论推导
程序将主动权交给用户,化主动为被动
-
IOC本质
- 控制反转IOC(Inversion of Control),是一种设计思想。在没有ioc的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,控制反转也就是将静态的代码转变为灵活的代码
- 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的
- 控制反转是一种通过描述(XMl或注解)并通过第三方去生产或获取特定对象的方式。在spring中实现控制反转的是IOC容器,其实现方法是依赖注入(Dependency Injection,DI)
-
IOC创建对象的方法
-
使用无参构造创建对象,默认
<property name="name" value="luo"/>
-
有参构造创建对象
-
下标赋值
<constructor-arg index="0" value="com.luo"/>
-
类型(不推荐使用,有局限性,相同类型出问题)
<constructor-arg type="java.lang.String" value="luo"/>
-
参数名
<constructor-arg name="name" value="luo"/>
总结:在配置文件加载的时候,容器中管理的对象就已经初始化了
-
-
三 Spring 配置
-
别名----alias
<!-- 别名——当id名字繁杂重复等问题,可以使用别名代替--> <alias name="user" alias="Users"/>
-
Bean常用基础配置----bean
<!-- id : bean的唯一标识符,相当于对象名 class : bean对象所对应的全限名 : 包名 + 类型 name : 别名,而且name可以同时取多个名字 --> <bean id="usert" class="com.luo.pojo.User" name="usert2,u2 t1;t2"></bean>
-
import
用于团队开发,可以将多个配置文件导入合并为一个(applicationContext.cml)。
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <import resource="beans.xml"/> <import resource="beans_li.xml"/> <import resource="beans_zhang.xml"/> </beans>
四 依赖注入
-
构造器注入
package com.luo.pojo; public class User { private String name; // 无参构造 // public User(){ // System.out.println("User的无参构造"); // } //有参构造 public User(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void show(){ System.out.println("name=" + name); } }
-
set方式注入
-
依赖注入:set注入
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的所有属性,由容器来注入
-
项目
-
实体类
package com.luo.pojo; import java.util.*; public class Student { private String name; private Address address; private String[] books; private List<String> hobbys; private Map<String,String> card; private Set<String> games; private String wife; private Properties info; public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public String[] getBooks() { return books; } public void setBooks(String[] books) { this.books = books; } public List<String> getHobbys() { return hobbys; } public void setHobbys(List<String> hobbys) { this.hobbys = hobbys; } public Map<String, String> getCard() { return card; } public void setCard(Map<String, String> card) { this.card = card; } public Set<String> getGames() { return games; } public void setGames(Set<String> games) { this.games = games; } public String getWife() { return wife; } public void setWife(String wife) { this.wife = wife; } public Properties getInfo() { return info; } public void setInfo(Properties info) { this.info = info; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", address=" + address.toString() + ", books=" + Arrays.toString(books) + ", hobbys=" + hobbys + ", card=" + card + ", games=" + games + ", wife='" + wife + '\'' + ", info=" + info + '}'; } }
-
测试类
import com.luo.pojo.Student; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Student student = (Student) context.getBean("student"); System.out.println(student.toString(); } }
-
bean.xml
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="address" class="com.luo.pojo.Address"> <property name="address" value="address"/> </bean> <bean id="student" class="com.luo.pojo.Student"> <!-- 一. 普通注入,value--> <property name="name" value="luo"/> <!-- 二. Bean注入,ref--> <property name="address" ref="address"/> <!-- 数组--> <property name="books"> <array> <value>红楼梦</value> <value>西游记</value> <value>水浒传</value> <value>三国演义</value> </array> </property> <!-- List --> <property name="hobbys"> <list> <value>写代码</value> <value>听音乐</value> <value>看电影</value> <value>打游戏</value> </list> </property> <!-- Map--> <property name="card"> <map> <entry key="账号" value="xxxxx@163.com"/> <entry key="密码" value="xxxxxx"/> </map> </property> <!-- Set--> <property name="games"> <set> <value>王者荣耀</value> <value>qq飞车</value> <value>光遇</value> </set> </property> <!-- null--> <property name="wife"> <null/> </property> <!-- Property--> <property name="info"> <props> <prop key="num">201927550318</prop> <prop key="name">酒城</prop> <prop key="gender">男</prop> </props> </property> </bean> </beans>
-
address.java
package com.luo.pojo; public class Address { private String address; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "Address{" + "address='" + address + '\'' + '}'; } }
-
-
-
扩展方式注入
-
userbeans.xml
<?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:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- p命名空间注入,可以直接注入属性的值:property--> <bean id="user" class="com.luo.pojo.User" p:name="luo" p:age="18"/> <!-- c命名空间注入,通过构造器注入:construct-args--> <bean id="user2" class="com.luo.pojo.User" c:age="19" c:name="luo" /> </beans>
-
usertest.java
import com.luo.pojo.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Usertest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml"); User user = context.getBean("user",User.class); System.out.println(user.toString()); } @Test public void test2(){ ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml"); User user2 = context.getBean("user2", User.class); System.out.println(user2.toString()); } }
-
User.java
package com.luo.pojo; public class User { private String name; private int age; public User() { } public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
注意:p命名与c命名不能直接使用,需导入xml约束。
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
-
五 Bean的作用域
作用域:singleton、prototype、request、session、application、websocket
- 单例模式(Spring默认机制)
<bean id="user2" class="com.luo.pojo.User" c:age="19" c:name="luo" scope="singleton" />
-
原型模式:每次从容器中get的时候,都会产生新的对象
<bean id="user2" class="com.luo.pojo.User" c:age="19" c:name="luo" scope="prototype" />
-
其余的request、session、session、application,只能在web开发中使用
六 Bean自动装配
-
自动装配式Spring满足bean依赖一种方式
-
Spring会在上下文自动寻找,并自动给bean装配属性
Dog.java
package com.luo.pojo; public class Dog { public void shout(){ System.out.println("wang~"); } }
Cat.java
package com.luo.pojo; public class Cat { public void shout(){ System.out.println("miao~"); } }
people.java
package com.luo.pojo; public class People { private Cat cat; private Dog dog; private String name; public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "People{" + "cat=" + cat + ", dog=" + dog + ", name='" + name + '\'' + '}'; } }
beans.xml
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="cat" class="com.luo.pojo.Cat"/> <bean id="dog" class="com.luo.pojo.Dog"/> <!-- <bean id="people" class="com.luo.pojo.People">--> <!-- <property name="name" value="luo"/>--> <!-- <property name="dog" ref="dog"/>--> <!-- <property name="cat" ref="cat"/>--> <!-- </bean>--> <!-- byName: 会自动在容器上下文中查找,和自己set方法后面的值对象的beanid byType: 会自动在容器上下文中查找,和自己对象属性类型相同的bean (可省略id,根据class判断) --> <bean id="people" class="com.luo.pojo.People" autowire="byType"> <property name="name" value="luo"/> </bean> </beans>
-
在spring中有三种装配方式
- 在xml中显示配置
- 在java中显示配置
- 隐式的自动装配bean
-
ByName自动装配
<!-- byName: 会自动在容器上下文中查找,和自己set方法后面的值对象的beanid--> <bean id="people" class="com.luo.pojo.People" autowire="byName"> <property name="name" value="luo"/> </bean>
-
ByType自动装配
<!-- byType: 会自动在容器上下文中查找,和自己对象属性类型相同的bean (可省略id,根据class判断) --> <bean class="com.luo.pojo.Cat"/> <bean class="com.luo.pojo.Dog"/> <bean id="people" class="com.luo.pojo.People" autowire="byType"> <property name="name" value="luo"/> </bean>
-
小结:
- byname,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法保持一致
- bytype,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性类型一致
-
使用注解实现自动装配
-
条件:
- 导入约束:context约束
- 配置注解的支持:context:annotation-config/
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/beans/spring-conext.xsd" > <!--开启注解自动装配 --> <context:annotation-config/>
-
@Autowired
-
直接在属性上使用,也可以在set方法上使用
-
使用Autowired后,可以不用编写set方法,前提是这个自动装配的属性在IOC(Spring)容器中存在,且符合名字byname/bytype
-
科普
@Nullable 字段标记了这个注解,说明这个字段可以为null
public @interface Autowired{ boolean required() default true; }
public class People{ //如果显示定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空 @Autowired(required = false) private Cat cat; @Autowired private Dog dog; private String name; }
如果@Autowired自动装配环境复杂,自动装配无法通过一个注解【@Autowired】完成的时候,可以使用【@Qualifier(value=“xxx”)】去配置@Autowired的使用,指定一个唯一的bean对象注入
-
-
@Resource注解
public class People{ @Resource(name = "xxx") private Cat cat ; @Resource private Dog dog ; }
小结:
@Autowired 与@Resource 的区别:
- @Autowired 通过spring,@Resource通过java (java11后被@Autowired取代)
- @Autowired 首先通过bytype的方式实现,其次byname
- @Resource 默认通过byname的方式实现,如果找不到名字,则通过bytype实现。(特殊:指定id或指定id和type)如果四个情况都找不到,则报错
七 使用注解开发
-
bean
-
属性如何注入(属性/set方法)
package com.luo.pojo; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; //@Component 等价于 <bean id="user" class="com.luo.pojo.User"/> @Component public class User { // public String name = "luo"; //相当于<property name="name" value="luo"/> // @Value("luo") public String name; @Value("luo") public void setName(String name) { this.name = name; } }
-
衍生的注解
@Component 有几个衍生注解,我们在web开发中,会按照mvc三层架构分层
-
dao【@Repository】
-
service【@Service】
-
controller【@Controller】
这四个注解功能是一样的,都代表将某个类注册到Spring中,装配Bean
-
-
自动装配
- @Autowired : 自动装配,默认类型其次id,如果Autowired不能唯一自动装配属性 ,则需要通过@Qualifier(value="xxx") - @Nullable : 字段标记了这个注解,说明这个字段可以为null - @Resource : 自动装配,默认id其次类型
-
作用域
与上面bean作用域类似一个写在xml文件一个写在java文件中
@Scope(“prototyper”)
-
小结
xml与注解:
- xml更加万能,适用于任何场景,维护简单方便
- 注解 不是自己类使用不了,有局限性,维护相对复杂
xml与注解最佳实践:
-
xml用来管理bean
-
注解只负责完成属性的注入
-
在使用的过程中要注意:必须让注解注解生效,就要开启注解支持
<!--指定要扫描的包,这个包下的注解就会生效 --> <context:component-scan base-package="com.luo"/> <context:annotation-config/>
-
八 JavaConfig配置
不使用Spring的xml配置,全权交给java
JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能
User.java(实体类)
package com.luo.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("luo")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
LuoConfig.java(配置类)
package com.luo.config;
import com.luo.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
//这个也会被Spring容器托管,注册到容器中,因为他本身就是一个@Component
//@Configuration代表这是一个配置类,就和我们之前看的beans.xml
@Configuration
//@ComponentScan 代表包扫描与xml中的类似
@ComponentScan("com.luo.pojo")
//Import : 导入多个配置文件
@Import(LuoConfigt.class)
public class LuoConfig {
//注册一个bean,相当于xml中的bean标签
//这个方法的名字,相当于bean标签的id属性
//这个方法的返回值,相当于bean标签的class属性
@Bean
public User getUser(){
return new User(); //返回要注入到bean的对象
}
}
LuoConfigt.java(配置类)
package com.luo.config;
import com.luo.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//这个也会被Spring容器托管,注册到容器中,因为他本身就是一个@Component
//@Configuration代表这是一个配置类,就和我们之前看的beans.xml
@Configuration
//@ComponentScan 代表包扫描与xml中的类似
@ComponentScan("com.luo.pojo")
public class LuoConfigt {
//注册一个bean,相当于xml中的bean标签
//这个方法的名字,相当于bean标签的id属性
//这个方法的返回值,相当于bean标签的class属性
@Bean
public User getUser(){
return new User(); //返回要注入到bean的对象
}
}
MyTest.java(测试类)
import com.luo.config.LuoConfig;
import com.luo.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyTest {
public static void main(String[] args) {
//如果完全使用了配置类,那么只能通过AnnotationConfig上下文获取容器,通过配置类的class对象加载
ApplicationContext context = new AnnotationConfigApplicationContext(LuoConfig.class);
User getUser = (User) context.getBean("getUser");
System.out.println(getUser.getName());
}
}
九 代理模式
代理模式是SpringAOP的底层
代理模式分为:
- 静态代理
- 动态代理
- 静态代理
- 角色分析
- 抽象角色:一般会使用接口或抽象类
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,做附属操作
- 客户:访问代理对象的人
- 角色分析
代理模式的好处:
- 真实业务由真实角色做,公共业务由代理角色做
- 公共业务就交给代理角色,实现业务的分工
- 公共业务发生扩展的时候,方便集中管理
代码步骤:
-
接口
package com.luo.demo01; public interface Rent { public void rent(); }
-
真实角色
package com.luo.demo01; public class Host implements Rent { @Override public void rent() { System.out.println("房东出租房子"); } }
-
代理角色
package com.luo.demo01; public class Proxy { private Host host; public Proxy(){ } public Proxy(Host host){ this.host= host; } public void rent(){ host.rent(); } public void seeHouse(){ System.out.println("中介带你看房"); } public void heTong(){ System.out.println("代签合同"); } }
-
客户端访问代理角色
package com.luo.demo01; public class Client { public static void main(String[] args) { Host host = new Host(); // host.rent(); Proxy proxy = new Proxy(host); proxy.rent(); proxy.seeHouse(); } }
代理模式的缺点:
- 一个真实角色会只产生一个代理角色;代码量翻倍,开发效率低
扩展深度理解:
在不修改源代码的基础上增加新的功能。
在程序开发中一般都是纵向开发,当我们程序上线后,客户要增加一个新的功能,这时候我们需要在不改动dao层的情况下对service层进行纵向开发也就是Aop。
代码演示:
UserService.java
package com.luo.demo02;
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
UserServiceImpl.java
package com.luo.demo02;
//真实对象
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void update() {
System.out.println("修改用户");
}
@Override
public void query() {
System.out.println("查询用户");
}
}
UserServiceProxy.java
package com.luo.demo02;
public class UserServiceProxy implements UserService{
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
@Override
public void add() {
log("add");
userService.add();
}
@Override
public void delete() {
log("delete");
userService.delete();
}
@Override
public void update() {
log("update");
userService.update();
}
@Override
public void query() {
log("query");
userService.query();
}
//日志方法
public void log(String msg){
System.out.println("使用了"+ msg + "方法");
}
}
Client.java
package com.luo.demo02;
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy userServiceProxy = new UserServiceProxy();
userServiceProxy.setUserService(userService);
userServiceProxy.add();
}
}
动态代理
- 动态代理和静态代理角色一样
- 动态代理的代理是动态生成的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口----JDK动态代理
- 基于类-----cglib
- java字节码----javasist
常用两个类:Proxy,InvocationHandler
十 Aop
-
Aop在Spring中的作用:提供声明式事务,允许用户自定义切面
-
依赖包
<dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> </dependencies>
-
实现方法
-
使用Spring API接口【主切点】
<aop:config> <!--切入点:expression:表达式,execution(要执行的位置 * * * * *)--> <aop:pointcut id="pointcut" expression="execution(* com.luo.service.UserServiceImp.*(..))"/> <!--执行环绕增加--> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config>
-
自定义类实现【主切面】
<aop:config> <!-- 自定义切面,ref 要引用的类--> <aop:aspect ref="diy"> <!--切入点--> <aop:pointcut id="point" expression="execution(* com.luo.service.UserServiceImp.*(..))"/> <!--通知 --> <aop:before method="before" pointcut-ref="point"/> <aop:after method="after" pointcut-ref="point"/> </aop:aspect> <!--方式三:注解 --> <bean id="annotationPointCut" class="com.luo.anno.AnnotationPointCut"/> <!--开启注解支持 JDK(默认 proxy-target-class="false") cglib(proxy-target-class="true") --> <aop:aspectj-autoproxy proxy-target-class="false"/> </aop:config>
-
注解实现aop
-
测试
Log.java
package com.luo.log; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class Log implements MethodBeforeAdvice { // method:要执行的目标对象的方法 //object:参数 //target:目标对象 @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了"); } }
AfterLog.java
package com.luo.log; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class AfterLog implements AfterReturningAdvice { @Override //returnValue:返回值 public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue); } }
UserService.java
package com.luo.service; public interface UserService { public void add(); public void delete(); public void update(); public void query(); }
UserServiceImp.java
package com.luo.service; public class UserServiceImp implements UserService{ @Override public void add() { System.out.println("增加用户"); } @Override public void delete() { System.out.println("删除用户"); } @Override public void update() { System.out.println("修改用户"); } @Override public void query() { System.out.println("查找用户"); } }
DiyPointCut.java
package com.luo.diy; public class DiyPointCut { public void before(){ System.out.println("方法前"); } public void after(){ System.out.println("方法后"); } }
AnnotationPointCut.java
package com.luo.anno; //使用注解实现aop import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect //标注这个类是一个切面 public class AnnotationPointCut { @Before("execution(* com.luo.service.UserServiceImp.*(..))") public void before(){ System.out.println("方法前"); } @After("execution(* com.luo.service.UserServiceImp.*(..))") public void after(){ System.out.println("方法后"); } @Around("execution(* com.luo.service.UserServiceImp.*(..))") public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("环绕前"); Signature signature = jp.getSignature();// 获得签名 System.out.println("signature:" + signature); //执行方法 Object proceed = jp.proceed(); System.out.println("环绕后"); System.out.println(proceed); } }
MyTest.java
import com.luo.diy.DiyPointCut; import com.luo.service.UserService; import com.luo.service.UserServiceImp; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) context.getBean("userService"); userService.add(); } }
applicationContext.xml
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd "> <!--注册bean--> <bean id="userService" class="com.luo.service.UserServiceImp"/> <bean id="log" class="com.luo.log.Log"/> <bean id="afterLog" class="com.luo.log.AfterLog"/> <!--方式一:使用原生Spring API接口--> <!--配置aop:导入aop约束--> <!-- <aop:config>--> <!-- <!–切入点:expression:表达式,execution(要执行的位置 * * * * *)–>--> <!-- <aop:pointcut id="pointcut" expression="execution(* com.luo.service.UserServiceImp.*(..))"/>--> <!-- <!–执行环绕增加–>--> <!-- <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>--> <!-- <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>--> <!-- </aop:config>--> <!--方式二:自定义类--> <bean id="diy" class="com.luo.diy.DiyPointCut"/> <aop:config> <!-- 自定义切面,ref 要引用的类--> <aop:aspect ref="diy"> <!--切入点--> <aop:pointcut id="point" expression="execution(* com.luo.service.UserServiceImp.*(..))"/> <!--通知 --> <aop:before method="before" pointcut-ref="point"/> <aop:after method="after" pointcut-ref="point"/> </aop:aspect> </aop:config> </beans>
-
十一 mybatis-spring
-
编写数据源配置
-
sqlSessionFactory
-
sqlSessionTemplate
-
给接口加实现类
-
注入spring
-
spring-dao.xml (spring_10_mybatis工程)
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd "> <!--DataSource:使用spring的数据源替换mybatis的配置 --> <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/fund?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/> <!-- <property name="url" value="jdbc:mysql://localhost:3306/fund?useSSL=ture"/>--> <property name="username" value="root"/> <property name="password" value="luo3306.J"/> </bean> <!-- sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 绑定mabatis配置文件 --> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:/com/luo/mapper/*.xml"/> </bean> <!-- SqlSessionTemplate:就是sqlSession --> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!-- 只能使用构造器注入sqlSessionFactory,因为没有set方法 --> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> <bean id="userMapper" class="com.luo.mapper.UserMapperImpl"> <property name="sqlSession" ref="sqlSession"/> </bean> </beans>
-
十二 声明式事务
-
事务
- 把一组业务当成一个业务来做,要么都成功,要么都失败;
- 事务在项目开发中,十分重要,涉及到数据的一致性
- 确保完整性和一致性
-
事务ACID原则:
- 原子性
- 一致性
- 隔离性
- 多个业务可能操作同一资源,防止数据损坏
- 持久性
- 事务一旦提交,无论系统发生什么问题,结果都不会被影响。
-
spring中的事务管理
- 声明式事务:AOP
- 编程式事务:需要在代码中进行事务管理
-
spring中7种Propagation类的事务属性详解
- REQUIRED(required) : 支持当前事务,如果当前没有事务,就新建一个事务。(常用)
- SUPPORTS(supports) : 支持当前事务,如果当前没有事务,就以非事务方式执行
- MANDATORY(mandatory) : 支持当前事务,如果当前没有事务,就抛出异常
- REQUIRES_NEW(requires_new) : 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
- NEVER(never) : 以非事务方式执行,如果当前存在事务,则抛出异常
- NESTED(nested) : 支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务
-
实例
UserMapper.java
package com.luo.mapper; import com.luo.pojo.User; import java.util.List; public interface UserMapper { public List<User> selectUser(); //添加数据 public int addFound(User user); // //删除数据 public int deleteFound(int id); }
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.luo.mapper.UserMapper"> <select id="selectUser" resultType="user"> <!-- fund.web 这是数据库 --> select * from fund.web; </select> <insert id="addFound" parameterType="user"> insert into fund.web(id,name,pwd) values(#{id},#{name},#{pwd}); </insert> <delete id="deleteFound" parameterType="int"> delete from fund.web where id=#{id} </delete> </mapper>
UserMapperImpl.java
package com.luo.mapper; import com.luo.pojo.User; import org.mybatis.spring.support.SqlSessionDaoSupport; import java.util.List; public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{ @Override public List<User> selectUser() { User user = new User(5, "小罗", "xiaoluo"); UserMapper mapper = getSqlSession().getMapper(UserMapper.class); mapper.addFound(user); mapper.deleteFound(4); return mapper.selectUser(); } @Override public int addFound(User user) { return getSqlSession().getMapper(UserMapper.class).addFound(user); } @Override public int deleteFound(int id) { return getSqlSession().getMapper(UserMapper.class).deleteFound(id); } }
User.java
package com.luo.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { private int id ; private String name; private String pwd;}
applicationContext.xml
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd "> <import resource="spring-dao.xml"/> <bean id="userMapper" class="com.luo.mapper.UserMapperImpl"> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean> </beans>
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <package name="com.luo.pojo"/> </typeAliases> </configuration>
spring-dao.xml
<?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:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd "> <!--DataSource:使用spring的数据源替换mybatis的配置 --> <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/fund?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="luo3306.J"/> </bean> <!-- sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 绑定mabatis配置文件 --> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:/com/luo/mapper/*.xml"/> </bean> <!-- SqlSessionTemplate:就是sqlSession --> <bean id="userMapper" class="org.mybatis.spring."> <!-- 只能使用构造器注入sqlSessionFactory,因为没有set方法 --> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> <!-- 配置声明式事务 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 结合AOP实现事务织入 --> <!-- 配置事务通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 给方法配置事务 --> <!-- 配置事务的传播特性:new --> <tx:attributes> <tx:method name="add" propagation="REQUIRED"/> <tx:method name="delete" propagation="REQUIRED"/> <tx:method name="update" propagation="REQUIRED"/> <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.luo.mapper.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config> </beans>
MyTest.java
import com.luo.mapper.UserMapper; import com.luo.pojo.User; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.List; public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); // for (User user : userMapper.selectUser()) { // System.out.println(user); // } List<User> users = userMapper.selectUser(); for (User user:users) { System.out.println(user); } } }
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>kuangshen-spring</artifactId> <groupId>org.spring</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>spring_11_transaction</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.20</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.19</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.19</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.2</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build> </project>
测试结果
User(id=1, name=李辰, pwd=lichen001) User(id=2, name=罗天宇, pwd=luotianyu002) User(id=3, name=会飞的鱼, pwd=huifeideyu003) User(id=5, name=小罗, pwd=xiaoluo)