GitHub:https://github.com/spring-projects/spring-framework
<?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">
</beans>
<!-- 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>
优点
- 开源免费框架
- 轻量级 非入侵式框架
- 控制反转(IOC) 面向切面(AOP)
- 支持事务的处理 支持框架整合
七大模块
IOC理论推导
- UserDao接口
public interface UserDao {
void getUser();
}
- UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("getUser");
}
}
public class UserDaoMysqlImpl implements UserDao {
@Override
public void getUser() {
System.out.println("mysql getUser");
}
}
- UserService接口
public interface UserService {
void getUser();
}
- UserServiceImpl
public class UserServiceImpl implements UserService {
private UserDao userDao;
// 利用set进行动态实现值的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
- Test
public class MyTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
((UserServiceImpl) userService).setUserDao(new UserDaoImpl());
((UserServiceImpl) userService).setUserDao(new UserDaoMysqlImpl());
userService.getUser();
}
}
控制反转 IOC
获得依赖对象的方式反转了,DI(依赖注入)只是控制反转的一种实现方式
Spring容器在初始化时先读取配置对象,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从IOC容器中取出需要的对象。
传统的应用程序的对象是程序本身控制创建的,使用Spring后,对象是由Spring创建的
HelloSpring
<?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">
<!-- 使用Spring创建对象 在Spring中都称为bean-->
<!--
类型 变量名 = new 类型();
Hello hello = new Hello();
id = 变量名
class = new 的对象
property 相当于给对象的属性设置值
-->
<bean id="hello" class="com.wang.pojo.Hello">
<property name="str" value="string"></property>
</bean>
</beans>
public class Hello {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
public class MyTest {
public static void main(String[] args) {
// 获取Spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 我们的对象都在Spring中管理了 要使用的时候在Spring取就可以
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
IOC创建对象的方式
- 使用无参构造创建对象 默认
<bean id="user" class="com.wang.pojo.User">
<property name="name" value="英豪"></property>
</bean>
- 假设我们要使用有参构造创建对象
<bean id="user" class="com.wang.pojo.User">
<!-- 第一种 下标赋值-->
<constructor-arg index="0" value="英豪"></constructor-arg>
</bean>
<bean id="user" class="com.wang.pojo.User">
<!-- 第二种 通过类型创建 不建议使用-->
<constructor-arg type="java.lang.String" value="英豪"></constructor-arg>
</bean>
<bean id="user" class="com.wang.pojo.User">
<!-- 第三种 通过参数名赋值-->
<constructor-arg name="name" value="英豪"></constructor-arg>
</bean>
总结:在配置文件加载的时候,容器中管理的bean已经初始化了
Spring的配置
Alias
<!-- 添加别名 也可以用别名获取到对象-->
<alias name="user" alias="user2"></alias>
Bean的配置
<!--
id: bean的唯一标识符
class:bean对象所对应的全限定名:包名+类型
name:也是别名,name更高级,可以同时取多个别名(逗号 空格 分号等都可以分隔)
scope="singleton" 单例 默认是单例 还可以是prototype session request
-->
<bean id="user" class="com.wang.pojo.User" name="user3,user4,user5" scope="singleton">
<constructor-arg name="name" value="英豪"></constructor-arg>
</bean>
import
一般是用于团队开发使用,可以将多个配置文件导入合并为一个
<?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>
<import resource="beans2.xml"></import>
</beans>
DI 依赖注入
构造器注入
前面已经说过了
set方式注入【重点】 需要无参构造器
- 依赖注入 Set注入
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的所有属性,由容器注入
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbies;
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> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
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 +
", books=" + Arrays.toString(books) +
", hobbies=" + hobbies +
", card=" + card +
", games=" + games +
", wife='" + wife + '\'' +
", info=" + info +
'}';
}
}
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 + '\'' +
'}';
}
}
<?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.wang.pojo.Address">
<property name="address" value="辽宁"></property>
</bean>
<bean id="student" class="com.wang.pojo.Student">
<property name="name" value="英豪"></property>
<property name="address" ref="address"></property>
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
<value>三国演义</value>
</array>
</property>
<property name="hobbies">
<list>
<value>听歌</value>
<value>代码</value>
<value>电影</value>
</list>
</property>
<property name="card">
<map>
<entry key="身份证" value="111111111"></entry>
<entry key="银行卡" value="2222222222"></entry>
</map>
</property>
<property name="games">
<set>
<value>LOL</value>
<value>COC</value>
<value>BOB</value>
</set>
</property>
<property name="wife">
<null></null>
</property>
<property name="info">
<props>
<prop key="学号">21022518</prop>
<prop key="性别">男</prop>
</props>
</property>
</bean>
</beans>
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);
// Student{
// name='英豪',
// address=Address{address='辽宁'},
// books=[红楼梦, 西游记, 水浒传, 三国演义],
// hobbies=[听歌, 代码, 电影],
// card={
// 身份证=111111111,
// 银行卡=2222222222},
// games=[LOL, COC, BOB],
// wife='null',
// info={
// 学号=21022518,
// 性别=男}}
}
}
拓展方式注入
<?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命名空间注入 可以直接注入属性的值 需要导入xml约束 xmlns:p="http://www.springframework.org/schema/p"-->
<bean id="user" class="com.wang.pojo.User" p:name="英豪" p:age="18"></bean>
<!-- c命名空间注入通过有参构造器注入 需要导入xml约束 xmlns:c="http://www.springframework.org/schema/c"-->
<bean id="user2" class="com.wang.pojo.User" c:age="18" c:name="英豪"></bean>
</beans>
bean的作用域
The Singleton Scope(默认)
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
The Prototype Scope 原型模式
每次从容器中get的时候都会新建一个新对象
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
Request, Session, Application, and WebSocket Scopes
web开发中使用
Bean的自动装配
- 自动装配是Spring满足bean依赖的一种方式
- Spring会在上下文中自动寻找,并自动给bean装配属性
在Spring中有三种装配方式:
- xml中显示配置
- 在java中显示配置
- 隐式自动装配
public class Cat {
public void shout() {
System.out.println("miao");
}
}
public class Dog {
public void shout() {
System.out.println("wang");
}
}
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 + '\'' +
'}';
}
}
<?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.wang.pojo.Cat"></bean>
<bean id="dog" class="com.wang.pojo.Dog"></bean>
<!-- <bean id="people" class="com.wang.pojo.People">-->
<!-- <property name="name" value="英豪"></property>-->
<!-- <property name="cat" ref="cat"></property>-->
<!-- <property name="dog" ref="dog"></property>-->
<!-- </bean>-->
<!-- 注入成功 byName会在容器上下文中查找 和自己对象set方法后面的值对应的bean id
上面Dog bean id改成 dog2222的话就会注入失败
-->
<!-- <bean id="people" class="com.wang.pojo.People" autowire="byName">-->
<!-- <property name="name" value="英豪"></property>-->
<!-- </bean>-->
<!-- 注入成功 byType会在容器上下文中查找 和自己对象属性类型对应相同的bean 但是如果存在两个类型相同的bean 比如 dog1 dog2 就会失败-->
<bean id="people" class="com.wang.pojo.People" autowire="byType">
<property name="name" value="英豪"></property>
</bean>
</beans>
ByName装配
<!-- 注入成功 byName会在容器上下文中查找 和自己对象set方法后面的值对应的bean id
上面Dog bean id改成 dog2222的话就会注入失败
-->
<!-- <bean id="people" class="com.wang.pojo.People" autowire="byName">-->
<!-- <property name="name" value="英豪"></property>-->
<!-- </bean>-->
ByType装配
<!-- 注入成功 byType会在容器上下文中查找 和自己对象属性类型对应相同的bean 但是如果存在两个类型相同的bean 比如 dog1 dog2 就会失败-->
<bean id="people" class="com.wang.pojo.People" autowire="byType">
<property name="name" value="英豪"></property>
</bean>
小结:
- byName需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
- byType的时候,需要保证所有bean的class唯一,并且这个bean和自动注入的属性的类型一致
使用注解自动装配
使用注解须知:
- 导入约束 context约束 xmlns:context=“http://www.springframework.org/schema/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"
xmlns: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/context/spring-context.xsd">
<context:annotation-config/>
</beans>
@Autowired
直接在属性上使用即可 也可以在set使用
使用Autowired可以不编写set方法,前提是自动装配的属性在IOC容器中存在
Autowired默认先按照byType装配 后byName
实测一:这个可以装配 说明是按照byType装配
<bean id="cat" class="com.wang.pojo.Cat"></bean>
<bean id="dog23" class="com.wang.pojo.Dog"></bean>
<bean id="people" class="com.wang.pojo.People"></bean>
实测二:这个可以装配 说明是按照byName装配
<bean id="cat" class="com.wang.pojo.Cat"></bean>
<bean id="dog23" class="com.wang.pojo.Dog"></bean>
<bean id="dog" class="com.wang.pojo.Dog"></bean>
<bean id="people" class="com.wang.pojo.People"></bean>
实测三:这个不可以装配
<bean id="cat" class="com.wang.pojo.Cat"></bean>
<bean id="dog23" class="com.wang.pojo.Dog"></bean>
<bean id="dog333" class="com.wang.pojo.Dog"></bean>
<bean id="people" class="com.wang.pojo.People"></bean>
@Nullable 字段标记了这个注解 说明这个字段可以为null
如果Autowired自动装配环境比较复杂,可以使用@Qualifier(value = “dog23”)配置使用,byName指定唯一注入
@Autowired
@Qualifier(value = "dog23")
private Dog dog;
@Resource java自带
使用注解开发
在Spring4之后,要使用注解开发,必须导入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
https://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>
- bean
- 属性如何注入
//等价于 <bean id = "user" class="com.wang.pojo.User"/>
@Component
public class User {
@Value("英豪")
public String name;
}
- 衍生的注解
@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层
- dao 【@Repository】
- service 【@Service】
- controller 【@Controller】
这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean,需要配置扫描
- 自动装配置
@Autowired
@Qualifier(
@Resource - 作用域
@Scope(value = “prototype”) - 小结
xml与注解
- xml更加万能,适用于任何场合 维护方便
- 注解 不是自己的类使用不了 维护相对复杂
xml与注解的最佳实践:
- xml管理bean
- 注解只负责完成属性注入
使用Java的方式配置Spring
我们现在完全不使用Spring的xml配置了,全权交给Java来做
JavaConfig是Spring的一个子项目,在Spring4之后成为了一个核心功能
AOP
代理模式:AOP的底层
代理模式分类:
- 静态代理
- 动态代理
静态代理
角色分析:
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
- 客户:访问代理对象的人
实现步骤:
- 接口
public interface Rent {
public void rent();
}
- 真实角色
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东出租房子");
}
}
- 代理角色
public class Proxy implements Rent {
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
seeHouse();
host.rent();
fare();
}
public void seeHouse() {
System.out.println("seeHouse");
}
public void fare() {
System.out.println("fare");
}
}
- 客户端访问
public class Client {
public static void main(String[] args) {
Host host = new Host();
host.rent();
}
}
代理模式的好处:
- 可以使真实角色的操作更加纯粹 不用去关注一些公共业务
- 公共业务交给代理角色 实现业务分工
- 公共业务发生扩展时 方便集中管理
缺点: - 一个真实角色产生一个代理角色 代码量翻倍
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("add");
}
@Override
public void delete() {
System.out.println("delete");
}
@Override
public void update() {
System.out.println("update");
}
@Override
public void query() {
System.out.println("query");
}
}
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);
}
}
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字节码实现:javassist
需要了解两个类:Proxy 代理 InvocationHandler 调用处理程序
Proxy 生成动态代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
InvocationHandler 调用处理程序并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 动态代理的本质 就是使用反射机制实现
Object result = method.invoke(target, args);
return result;
}
动态代理的好处:
- 可以使真实角色的操作更加纯粹 不用去关注一些公共业务
- 公共业务交给代理角色 实现业务分工
- 公共业务发生扩展时 方便集中管理
- 一个动态代理类代理的是一个接口 一般就是对应的一类业务
- 一个动态代理类可以代理多个类 只要是实现了同一个接口即可
/**
* @Description: 用这个类动态生成代理类
* @Author: wangyinghao
* @Date: 2020-06-09 10:26
**/
public class ProxyInvocationHandler 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);
}
//处理代理实例并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
// 动态代理的本质 就是使用反射机制实现
Object result = method.invoke(target, args);
return result;
}
public void log(String msg) {
System.out.println(msg);
}
}
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
//代理角色 现在没有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService);
UserService proxy = (UserService) pih.getProxy();
proxy.add();
}
}
AOP
什么是AOP:
面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分隔离,从而使得业务逻辑各个部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
使用Spring实现AOP
导入依赖包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
方式一:使用Spring的API接口
public interface UserService {
public void add();
public void delete();
public void update();
public void select();
}
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 select() {
System.out.println("查询了一个用户");
}
}
public class AfterLog implements AfterReturningAdvice {
// returnValue 返回值
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了" + method.getName() + "方法,返回结果为" + returnValue);
}
}
public class Log implements MethodBeforeAdvice {
// method 要执行的目标对象的方法
// objects 参数
// o 目标对象
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName() + "的" + method.getName() + "被执行了");
}
}
<?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.wang.service.UserServiceImpl"></bean>
<bean id="log" class="com.wang.log.Log"></bean>
<bean id="afterLog" class="com.wang.log.AfterLog"></bean>
<!-- 配置AOP 需要导入aop约束-->
<aop:config>
<!--切入点 expression 表达式 execution 要执行的位置-->
<aop:pointcut id="pointcut" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>
<!-- 执行环绕增强-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
</beans>
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
}
方式二:自定义类实现AOP
public class DiyPointCut {
public void before(){
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"
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.wang.service.UserServiceImpl"></bean>
<bean id="log" class="com.wang.log.Log"></bean>
<bean id="afterLog" class="com.wang.log.AfterLog"></bean>
<!-- 方式一 使用原生Spring API接口-->
<!-- 配置AOP 需要导入aop约束-->
<!-- <aop:config>-->
<!-- <!–切入点 expression 表达式 execution 要执行的位置–>-->
<!-- <aop:pointcut id="pointcut" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>-->
<!-- <!– 执行环绕增强–>-->
<!-- <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>-->
<!-- <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>-->
<!-- </aop:config>-->
<!-- 方式二 自定义类-->
<bean id="diy" class="com.wang.diy.DiyPointCut"></bean>
<aop:config>
<aop:aspect ref="diy">
<!-- 切入点-->
<aop:pointcut id="point" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>
<!-- 通知-->
<aop:before method="before" pointcut-ref="point"></aop:before>
<aop:after method="after" pointcut-ref="point"></aop:after>
</aop:aspect>
</aop:config>
</beans>
方式三:使用注解实现
/**
* @Description: 使用注解方式实现AOP
* @Author: wangyinghao
* @Date: 2020-06-10 10:52
**/
@Aspect // 标注这个类是个切面
public class AnnotationPointCut {
@Before("execution(* com.wang.service.UserServiceImpl.*(..))")
public void before() {
System.out.println("=====方法执行前=====");
}
@After("execution(* com.wang.service.UserServiceImpl.*(..))")
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"
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.wang.service.UserServiceImpl"></bean>
<bean id="log" class="com.wang.log.Log"></bean>
<bean id="afterLog" class="com.wang.log.AfterLog"></bean>
<!-- 方式一 使用原生Spring API接口-->
<!-- 配置AOP 需要导入aop约束-->
<!-- <aop:config>-->
<!-- <!–切入点 expression 表达式 execution 要执行的位置–>-->
<!-- <aop:pointcut id="pointcut" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>-->
<!-- <!– 执行环绕增强–>-->
<!-- <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>-->
<!-- <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>-->
<!-- </aop:config>-->
<!-- 方式二 自定义类-->
<!-- <bean id="diy" class="com.wang.diy.DiyPointCut"></bean>-->
<!-- <aop:config>-->
<!-- <aop:aspect ref="diy">-->
<!-- <!– 切入点–>-->
<!-- <aop:pointcut id="point" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>-->
<!-- <!– 通知–>-->
<!-- <aop:before method="before" pointcut-ref="point"></aop:before>-->
<!-- <aop:after method="after" pointcut-ref="point"></aop:after>-->
<!-- </aop:aspect>-->
<!-- </aop:config>-->
<!-- 方式三-->
<bean id="annotationPointCut" class="com.wang.diy.AnnotationPointCut"></bean>
<!-- 开启注解支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
整合Mybatis
步骤:
- 导入相关jar包
- junit
- mybatis
- mysql数据库
- spring相关
- aop
- mybatis-spring
<?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-study</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-10-mybatis</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</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.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>
</dependencies>
</project>
- 编写配置文件
- 测试
- 编写数据源配置
<!-- DataSource 使用Spring数据源替换Mybatis的配置 c3p0 dbcp druid-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url"
value="jdbc:mysql://aliyun:3306/mybatis?useUnicode=true&characterEncoding=UTF-8"></property>
<property name="username" value="root"></property>
<property name="password" value="Lndlwyh919190."></property>
</bean>
- sqlSessionFactory
<!-- sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!-- 绑定mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:com/wang/mapper/*.xml"></property>
</bean>
- sqlSessionTemplate
<!-- sqlSessionTemplate就是我们使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 只能用构造器注入 因为SqlSessionTemplate没set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
- 给接口加实现类
public interface UserMapper {
List<User> selectUser();
}
public class UserMapperImpl implements UserMapper {
// 我们所有操作都是用sqlSessionTemplate执行
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<User> selectUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
<mapper namespace="com.wang.mapper.UserMapper">
<select id="selectUser" resultType="User">
select * from mybatis.user;
</select>
</mapper>
<bean id="userMapper" class="com.wang.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"></property>
</bean>
- 测试
public class MyTest {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
for (User user : userMapper.selectUser()) {
System.out.println(user.toString());
}
}
}
声明式事务
事务的ACID原则
- 原子性
- 一致性
- 隔离性
- 持久性
Spring中的事务
- 声明式事务 AOP
- 编程式事务:需要在代码中 进行事务管理