Spring : 春天--->给软件行业带来了春天!
2002年,首次推出了Spring框架的雏形;interface21框架!
spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,与2004年3月24日发布了1.0正式版。
spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!
SSH:Struct2 + Spring + Hibernate!
SSM:PsringMVC + Spring + Mybatis!
使用下载:
pom.xml
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.1.4</version>
</dependency>
首先创建一个Maven项目
导入spring依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.10</version> <!-- 选择与Java 8兼容的Spring版本 -->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
</dependencies>
模拟一个业务场景;
代码结构:
User类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String dataSources;
}
UserDAO
public interface UserDAO {
// 获取一个用户
User getUser();
}
UserDAOImpl
public class UserADOImpl implements UserDAO{
@Override
public User getUser() {
return new User("mysql查询用户!");
}
}
UserService
public interface UserService {
// 获取用户数据并输出
void outUserData();
}
UserServiceImpl
public class UserServiceImpl implements UserService{
// 构建ADO对象
private UserDAO userDAO = new UserADOImpl();
@Override
public void outUserData() {
System.out.println(userDAO.getUser());
}
}
测试:
UserService userService = new UserServiceImpl();
userService.outUserData();
现在新增DAO的实现类了:
public class OracleUserDAOImpl implements UserDAO{
@Override
public User getUser() {
return new User("oracle查询用户!");
}
}
现在在Service想换一个实现类调用,我们就需要修改代码:
运行测试:
也完成了需求:
但是这种方式,首先我们需要不断修改Service层的代码,显然不太合理,所以我们现在就可以利用IOC的思想来修改代码如下:
public class UserServiceImpl implements UserService{
// 构建ADO对象
private UserDAO userDAO;
public UserServiceImpl(UserDAO userDAO){
this.userDAO = userDAO;
}
@Override
public void outUserData() {
System.out.println(userDAO.getUser());
}
}
需要使用哪一种,就传入对应的实例化对象就可以了,测试使用:
UserService userService = new UserServiceImpl(new UserADOImpl());
userService.outUserData();
userService = new UserServiceImpl(new OracleUserDAOImpl());
userService.outUserData();
利用了IOC的思想就可以灵活的处理现在的这个业务场景,当我们需要那个实现的时候,就传入对应的实现即可;
ioc的本质:
<?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">
<!-- 通过配置文件创建一个userBean的对象 id=获取时的名字 class是创建的具体类的全类名 -->
<bean id="user" class="com.huaijiuwang.pojo.User" >
<!-- 配置对象的属性值,注意:使用这个属性必须有对应的set方法,不然就会报错 -->
<property name="dataSources" value="mysql驱动" />
</bean>
</beans>
// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过对象获取一个bean的实例
User user = (User) context.getBean("user");
// 输出对象数据
System.out.println(user);
在获取一个对象:
// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过对象获取一个bean的实例
User user = (User) context.getBean("user");
System.out.println(user);
User user1 = (User) context.getBean("user");
System.out.println(user1);
System.out.println(user == user1);
通过测试发现:这个bean对象是一个单例的对象,始终自能返回同一个对象,要想让对象不容,就只能创建多个配置bean:
<!-- 通过配置文件创建一个userBean的对象 id=获取时的名字 class是创建的具体类的全类名 -->
<bean id="user" class="com.huaijiuwang.pojo.User" >
<!-- 配置对象的属性值,注意:使用这个属性必须有对应的set方法,不然就会报错 -->
<property name="dataSources" value="mysql驱动" />
</bean>
<bean id="user1" class="com.huaijiuwang.pojo.User" >
<property name="dataSources" value="oracle驱动" />
</bean>
// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过对象获取一个bean的实例
User user = (User) context.getBean("user");
System.out.println(user);
User user1 = (User) context.getBean("user1");
System.out.println(user1);
System.out.println(user == user1);
注意:对象必须有一个空参的构造方法,不然就会报错,或者创建bean的时候使用指定构造方法创建
思考问题:
修改之前的实体类:
public class User {
private String dataSources;
public User() {
System.out.println("执行空参构造方法!");
}
public User(String dataSources) {
this.dataSources = dataSources;
System.out.println("执行有参构造方法!");
}
public String getDataSources() {
return dataSources;
}
public void setDataSources(String dataSources) {
this.dataSources = dataSources;
}
public String toString() {
return "User{dataSources = " + dataSources + "}";
}
}
注册bean:
<?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">
<bean id="user" class="com.huaijiuwang.pojo.User" />
</beans>
// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
当程序一运行就执行了构造方法,说明当前的对象是在程序一启动就创建好了,现在就子需要等待用户的使用了。
// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过对象获取一个bean的实例
User user = (User) context.getBean("user");
System.out.println(user);
测试,删除无参构造方法:
程序加载的时候就直接报错了;
运行结果如下:
bean默认是调用对象的无参构造方法,当对象没有无参构造方法时,我们就需要手动调用有参的构造方法:
调用有参构造方法有一下三种:
<bean id="user" class="com.huaijiuwang.pojo.User">
<constructor-arg index="0" value="怀旧..." />
</bean>
<bean id="user" class="com.huaijiuwang.pojo.User">
<constructor-arg type="java.lang.String" value="怀旧666" />
</bean>
<bean id="user" class="com.huaijiuwang.pojo.User">
<constructor-arg name="dataSources" value="怀旧111" />
</bean>
配置文件
<!-- 创建mysql的实现 -->
<bean id="userDao" class="com.huaijiuwang.dao.UserADOImpl" />
<!-- 创建oracle的实现 -->
<bean id="oracleDao" class="com.huaijiuwang.dao.OracleUserDAOImpl" />
<!-- 创建service的bean -->
<bean id="userService" class="com.huaijiuwang.service.UserServiceImpl">
<!-- 这边创建的时候就需要使用带参数的构造方法,不然就会报错
之前里是通过value进行复制的,这边是使用的ref给对象赋值,这边的赋值内容就是上面创建的bean的引用
相当于这边传入的就是上面创建的实例对象.
-->
<constructor-arg index="0" ref="oracleDao" />
</bean>
编写测试方法:
// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过对象获取一个bean的实例
UserService userService = (UserService) context.getBean("userService");
userService.outUserData();
运行输出:
当我们想切换实现类的时候,直接修改配置文件:
<bean id="userService" class="com.huaijiuwang.service.UserServiceImpl">
<!-- 这边创建的时候就需要使用带参数的构造方法,不然就会报错 -->
<constructor-arg index="0" ref="userDao" />
</bean>
直接修改配置文件就可以实现对象的替换,在以后修改实现对象的时候就不需要修改java代码,可以修改配置文件来实现。
使用 alias 标签可以给当前创建的bean创建一个别名,也就意味着可以通过原来的bean id获取对象,现在还可以通过别名也获取对象;
给user对象配置别名
<bean name="user" class="com.huaijiuwang.pojo.User" >
<constructor-arg name="dataSources" value="怀旧" />
</bean>
<!-- 配置别名 -->
<alias name="user" alias="user1" />
使用测试:
// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user);
User user1 = (User) context.getBean("user1");
System.out.println(user1);
System.out.println(user == user1);
通过测试发现我们可以通过两个不同的名称,都可以获取到user对象,并且他们指向的也是同一个地址。
就是前面讲过的那三种方式;
创建一个包含所有类型的复制实体类:
@Data
public class Address {
private String address;
}
@Data
public class User {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String, String> card;
private Set<String> games;
private Properties info;
private String wife;
}
测试第一种:字符串数据注入:
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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.huaijiuwang.pojo.User">
<!-- 第一种字符串数据类型直接通过value注入 -->
<property name="name" value="怀旧" />
</bean>
</beans>
测试:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user.getName());
第二种Bean注入 使用 ref:
<!-- 第二种Bean注入 使用 ref -->
<property name="address" ref="address" />
第三种:数组注入:
<!-- 第三种数组注入 -->
<property name="books">
<array>
<value>书1</value>
<value>书1</value>
<value>书1</value>
</array>
</property>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(Arrays.toString(user.getBooks()));
第四种:list注入:
<!-- 第四种list注入 -->
<property name="hobbys">
<list>
<value>爱好1</value>
<value>爱好2</value>
<value>爱好3</value>
</list>
</property>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user.getHobbys());
第五种:map注入:
<!-- 第五种map注入 -->
<property name="card">
<map>
<entry key="key1" value="value1" />
<entry key="key2" value="value2" />
<entry key="key3" value="value3" />
</map>
</property>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user.getCard());
第六种:set注入:
<!-- 第六种set注入 -->
<property name="games">
<set>
<value>游戏1</value>
<value>游戏2</value>
<value>游戏3</value>
</set>
</property>
第七种:null注入:
正常情况下数据不写是一个空字符串:如果想实现null注入就需要一下配置:
<!-- 第七种 null 注入 -->
<property name="wife">
<null />
</property>
第八种:properties注入:
<!-- 第八种 properties 注入 -->
<property name="info">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
Properties info = user.getInfo();
System.out.println(info.getProperty("username"));
System.out.println(info.getProperty("password"));
我们可以使用p命名空间和c命名空间进行注入;
使用前先导入需要的头命名空间:
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
// 需要写下面两个命名空间
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
p命名空间使用(set方式注入--替换property属性):
编写java类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private int age;
}
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.huaijiuwang.pojo.User" p:name="怀旧" p:age="18" />
</beans>
测试:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user", User.class);
System.out.println(user);
c命名空间方式注入(其实就是通过构造器注入):
@Data
public class User {
private String name;
private int age;
public User(String name, int age) {
System.out.println("有参构造方法调用!");
this.name = name;
this.age = age;
}
}
<bean id="user1" class="com.huaijiuwang.pojo.User" c:age="15" c:name="怀旧2" />
Bean 的默认作用域就是单例的:
测试:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user1", User.class);
User user1 = context.getBean("user1", User.class);
System.out.println(user == user1);
通过案例可以看到构造方法只呗调用了一次,而且是在没有获取bean的时候就已经加载了。并且两次获取的都是同一个对象地址;
我们可以显示的给作用域赋值:
<bean id="user1" class="com.huaijiuwang.pojo.User" c:age="15" c:name="怀旧2" scope="singleton" />
测试原型模式:
修改配置:
<bean id="user1" class="com.huaijiuwang.pojo.User" c:age="15" c:name="怀旧2" scope="prototype" />
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
有参构造没有被调用
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user1", User.class);
System.out.println(user);
User user1 = context.getBean("user1", User.class);
System.out.println(user1);
System.out.println(user == user1);
调用了两次构造方法,并且两个对象是不同的两个地址;
编写测试:
模拟场景,一个用户,拥有连个宠物,分别是猫和狗:
public class Cat {
public void shout(){
System.out.println("猫叫...");
}
}
public class Dog {
public void shout(){
System.out.println("狗叫...");
}
}
@Data
public class User {
private String name;
private Cat cat;
private Dog dog;
}
编写xml:
<bean id="cat" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog" class="com.huaijiuwang.pojo.Dog" />
<bean id="user" class="com.huaijiuwang.pojo.User" p:name="怀旧"
p:cat-ref="cat" p:dog-ref="dog" />
使用测试:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user", User.class);
user.getCat().shout();
user.getDog().shout();
测试完成:
用上面的方式来实现十分麻烦,现在使用自动装配来实现:
方式一(byName):
<bean id="user" class="com.huaijiuwang.pojo.User" autowire="byName" />
同样运行成功!
但是这边注意,我们使用autowire自动注入,里面的值为byName的时候:
修改名称后测试:
<bean id="cat" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog1" class="com.huaijiuwang.pojo.Dog" />
<bean id="user" class="com.huaijiuwang.pojo.User" autowire="byName" />
运行报错!
方式二(byType):
测试:
<bean id="cat" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog1" class="com.huaijiuwang.pojo.Dog" />
<bean id="user" class="com.huaijiuwang.pojo.User" autowire="byType" />
但是:
因为byType是根据类型定义,所以就算前面定义的bean没有名称同样可以注入成功;
<bean class="com.huaijiuwang.pojo.Cat" />
<bean class="com.huaijiuwang.pojo.Dog" />
<bean id="user" class="com.huaijiuwang.pojo.User" autowire="byType" />
要使用注解需要知道:
<?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">
</beans>
<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/>
<bean id="cat" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog" class="com.huaijiuwang.pojo.Dog" />
<bean id="user" class="com.huaijiuwang.pojo.User"/>
</beans>
@Data
public class User {
private String name;
@Autowired
private Cat cat;
@Autowired
private Dog dog;
}
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user", User.class);
user.getCat().shout();
user.getDog().shout();
直接通过在属性上面添加注解就完成了注入;
也可以写在属性的set方法上面也可以,这边就不做演示了。
注意:因为这个自动注入是使用反射实现的所以我们注入的属性不需要有set方法也可以完成注入;
测试之前的方式,当 当前配置的bean没有名称:
<?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/>
<bean class="com.huaijiuwang.pojo.Cat" />
<bean class="com.huaijiuwang.pojo.Dog" />
<bean id="user" class="com.huaijiuwang.pojo.User"/>
</beans>
同样能够自动注入,就代表@Autowired注解可以自动根据类型来装配
如果我们有多个bean的时候,我们也可以通过@Qualifier("cat1")来实现
<context:annotation-config/>
<bean id="cat1" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog1" class="com.huaijiuwang.pojo.Dog" />
<bean id="cat2" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog2" class="com.huaijiuwang.pojo.Dog" />
<bean id="user" class="com.huaijiuwang.pojo.User"/>
@Data
public class User {
private String name;
@Autowired
@Qualifier("cat1")
private Cat cat;
@Autowired
@Qualifier("dog1")
private Dog dog;
}
@Data
public class User {
private String name;
@Autowired
@Qualifier("cat2")
private Cat cat;
@Autowired
@Qualifier("dog2")
private Dog dog;
}
<bean id="cat" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog" class="com.huaijiuwang.pojo.Dog" />
<bean id="user" class="com.huaijiuwang.pojo.User"/>
@Data
public class User {
private String name;
@Resource
private Cat cat;
@Resource
private Dog dog;
}
<bean id="cat22" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog22" class="com.huaijiuwang.pojo.Dog" />
<bean id="user" class="com.huaijiuwang.pojo.User"/>
@Data
public class User {
private String name;
@Resource
private Cat cat;
@Resource
private Dog dog;
}
<bean class="com.huaijiuwang.pojo.Cat" />
<bean class="com.huaijiuwang.pojo.Dog" />
<bean id="user" class="com.huaijiuwang.pojo.User"/>
<bean id="cat1" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog1" class="com.huaijiuwang.pojo.Dog" />
<bean id="cat2" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog2" class="com.huaijiuwang.pojo.Dog" />
<bean id="user" class="com.huaijiuwang.pojo.User"/>
当通过byName和byType都找不到的时候就会报错了:
但是现在可以修改注解来实现通过Bean id注入
@Data
public class User {
private String name;
@Resource(name = "cat1")
private Cat cat;
@Resource(name = "dog1")
private Dog dog;
}
在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>
<!-- 指定要扫描的包,这个包下面的注解就会生效 -->
<context:component-scan base-package="com.huaijiuwang.pojo" />
首先需要配置注解扫码:
<context:component-scan base-package="com.huaijiuwang.pojo" />
创建实体类(在实体类上面加上@Component注解即可):
@Data
// 等价于:<bean id="user" class="com.huaijiuwang.pojo.User" />
@Component
public class User {
private String name = "怀旧";
}
测试:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user", User.class);
System.out.println(user);
这个注解可以放在属性或者属性的set方法上
@Data
@Component
public class User {
// 等价于: <property name="name" value="怀旧" />
@Value("怀旧")
private String name;
}
@Component 有几个衍生的注解,我们在web开发中,会按照mvc三层架构分层!
这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean!
就是上面讲到的所有的自动注入属性值的那几个注解!
因为每个包下面都有类;所以我们的注解扫描就需要配置到每一个类:
<context:component-scan base-package="com.huaijiuwang" />
User.java
@Data
@Component
public class User {
@Value("怀旧")
private String name;
}
UserDao.java
@Repository
public class UserDao {
@Autowired
private User user;
public User getUser(){
return this.user;
}
}
UserService.java
@Service
public class UserService {
@Autowired
private UserDao userDao;
public User getUser(){
return this.userDao.getUser();
}
}
UserController.java
@Controller
public class UserController {
@Autowired
private UserService userService;
public void showUser(){
System.out.println(this.userService.getUser());
}
}
测试:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserController userController = context.getBean("userController", UserController.class);
userController.showUser();
@Scope 注解:和配置中编写的一样可以设定bean的作用域,默认还是singleton单例模式:
@Data
@Component
// 等价于:<bean id="user" class="com.huaijiuwang.pojo.User" scope="singleton" />
@Scope("singleton")
public class User {
@Value("怀旧")
private String name;
}
测试多例模式:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user", User.class);
User user1 = context.getBean("user", User.class);
System.out.println(user == user1);
完全通过java来配置Spring,首先就可以删除所有的xml配置文件:
1.创建一个配置类,用来代替.xml文件
@Configuration
public class MyConfig {
}
在代码中添加@Configuration注解,指定当前的类是一个配置类---.xml文件
这个注解本身还继承了@Component注解,说明这个注解本身就是一个bean
编写一个实体类用于测试:
@Data
public class User {
private String name;
}
我们创建的这个类,没有添加@Component注解,说明当前的实体类没有被加载到Spring的容器中托管,我们现在就可以通过配置类来实现,我们之前的注册Bean实现:
@Configuration
public class MyConfig {
// 这个必须写,指定当前的返回值就是当前获取的Bean实例
@Bean
public User getUser(){
User user = new User();
user.setName("通过配置类注册bean");
return user;
}
}
使用测试:
因为现在我们使用的是配置类,所以就不能使用之前的new ClassPathXmlApplicationContext() 这个来获取context对象了:
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
User user = context.getBean("getUser", User.class);
System.out.println(user);
成功获取bean的对象
在获取bean的时候,我们的context.getBean("getUser", User.class); getbean的名称是需要指定注册@Bean的方法名来确定的
修改bean名称就会报错:
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
User user = context.getBean("user", User.class);
System.out.println(user);
测试获取的是否是同一个对象
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
User user = context.getBean("getUser", User.class);
User user1 = context.getBean("getUser", User.class);
System.out.println(user == user1);
通过输出可以看出获取到的是同一个对象:
我们现在就需要将当前的属性改为多例模式:
@Bean
@Scope("prototype")
public User getUser(){
User user = new User();
user.setName("通过配置类注册bean");
return user;
}
我们bean配置就可以直接在这边实现了!
在正常的xml配置中,可能遇到多个.xml文件,这个时候我们之前的做法是通过import标签来导入其他的配置文件进行汇众:现在我们可以通过注解的方式来实现:
例如现在又创建了一个配置类MyConfig1
@Configuration
public class MyConfig1 {
@Bean
public User user1(){
User user = new User();
user.setName("通过配置类1注册bean");
return user;
}
}
现在我们想使用user1这个bean,我们还是通过之前的代码获取
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
User user = context.getBean("user1", User.class);
System.out.println(user);
会报错,因为加载的不是我们配置user1的配置类,修改配置类
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig1.class);
User user = context.getBean("user1", User.class);
System.out.println(user);
但是这样以后,我们配置的MyConfig的bean又无法加载了
所以现在就需要让两个配置类进行合并:使用@Import注解来导入其他配置
@Configuration
@Import(MyConfig1.class)
public class MyConfig {
@Bean
public User getUser(){
User user = new User();
user.setName("通过配置类注册bean");
return user;
}
}
现在测试:
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
User user = context.getBean("getUser", User.class);
User user1 = context.getBean("user1", User.class);
System.out.println(user);
System.out.println(user1);
两个地方的bean都可以被加载到;
在配置xml的时候我们可以配置宝的扫描,让其他的包同样可以使用注解,现在我们也可以通过在配置类添加注解来实现:
@Configuration
@Import(MyConfig1.class)
@ComponentScan("com.huaijiuwang.pojo")
public class MyConfig {
}
修改实体类;删除配置中注册的bean
@Data
@Component
public class User {
@Value("通过注解注入值(配置注解包扫描)....")
private String name;
}
测试:
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
User user = context.getBean("user", User.class);
System.out.println(user);
模拟我们吃饭:
在我们吃饭的过程中,我们需要先有饭,然后我们在吃饭,吃完饭之后别人来洗碗:
在上面的案例中,我们就是一个被代理的对象
代码步骤:
1.接口
public interface Eat {
void eat();
}
2.真实角色(我,去吃饭)
public class User implements Eat{
@Override
public void eat() {
System.out.println("我开始吃饭了!");
}
}
3.代理角色(实现做饭,提供我可以吃饭,洗碗)
public class AgentUser implements Eat{
// 被代理的角色(我)
private User user;
public AgentUser(User user) {
this.user = user;
}
@Override
public void eat() {
// 在用户吃饭前,需要做饭
this.before();
// 让用户来吃饭了
this.user.eat();
// 用户吃完饭,洗碗
this.after();
}
private void before(){
System.out.println("开始做饭!!");
}
private void after(){
System.out.println("开始洗碗!!");
}
}
4.测试:
User user = new User();
AgentUser agentUser = new AgentUser(user);
agentUser.eat();
需要用到两个类:Proxy: 代理, InvocationHandler: 调用处理程序
实现步骤:
1.创建实现动态代理的类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandler implements InvocationHandler {
// 需要被代理的对象
private Object target;
// 需要被代理的对象,初始化就需要构造出来
public MyInvocationHandler(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 {
// 方法执行前可以调用方法
before();
// 执行方法,并获得返回值
Object result = method.invoke(target, args);
// 方法执行后可以调用方法
after();
return result;
}
private void before(){
System.out.println("开始做饭!!");
}
private void after(){
System.out.println("开始洗碗!!");
}
}
被代理的对象:
public class User implements Eat{
@Override
public void eat() {
System.out.println("我开始吃饭了!");
}
}
使用测试:
// 创建被代理对象
User user = new User();
// 创建 生成代理类的实力,并传入需要被代理的类的对象
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(user);
// 获取真实的代理类对象
Eat eat = (Eat) myInvocationHandler.getProxy();
// 执行代理后的方法
eat.eat();
1.确保当前有AOP的包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
2.创建一个业务,模拟一个service
UserService.java
public interface UserService {
void add();
void update();
void delete();
void select();
}
UserServiceImpl.java
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("添加一个用户...");
}
@Override
public void update() {
System.out.println("修改一个用户...");
}
@Override
public void delete() {
System.out.println("删除一个用户...");
}
@Override
public void select() {
System.out.println("查询一个用户...");
}
}
3.创建aop代理执行前后的类
MyBefore.java
// 配置被代理对象执行前
public class MyBefore implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName() + " 类 " + method.getName() + " 方法被执行了!");
}
}
MyAfter.java
// 配置被代理对象执行后
public class MyAfter implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName() + " 方法执行完毕了!");
}
}
创建被代理对象bean 使用.xml文件配置
<bean id="userService" class="com.huaijiuwang.service.UserServiceImpl" />
<bean id="myBefore" class="com.huaijiuwang.aop.MyBefore" />
<bean id="myAfter" class="com.huaijiuwang.aop.MyAfter" />
配置aop
配置规则:
在面向切面编程(AOP)中,切入点(Pointcut)用于定义在哪些方法或代码段上应该应用切面的逻辑。切入点使用表达式来匹配目标方法的签名和执行位置。
在Spring AOP 中,常用的切入点表达式是基于方法的 execution
表达式。execution
表达式由访问修饰符、返回类型、类名、方法名和参数列表组成,具体格式如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
其中,各个部分的含义如下:
modifiers-pattern(可选):指定方法的访问修饰符,如 public、private 等。 ret-type-pattern:指定方法的返回类型,如 int、void 等。使用通配符 * 可表示任意返回类型。 declaring-type-pattern(可选):指定方法所属的类名或包名。例如,com.example.Service 表示匹配 com.example 包下的所有以 “Service” 结尾的类。 name-pattern:指定方法名,可以使用通配符 * 表示任意方法名,如 get 表示以 “get” 开头的方法。 param-pattern:指定方法的参数列表。例如,(String, *) 表示第一个参数为 String 类型,第二个参数为任意类型。 throws-pattern(可选):指定方法可能抛出的异常。
<aop:config>
<!-- 配置当前aop需要让那些方法进行代理 这里配置的就是所有修饰的方法 并且是UserServiceImpl下任意参数所有的方法
id指的是一个标识,用来标识当前这个配置路径
-->
<aop:pointcut id="pointcut" expression="execution(* com.huaijiuwang.service.UserServiceImpl.*(..))"/>
<!-- 配置切入的bean(就是执行前后调用的方法生效在当前id对应到的指向的代理的位置) -->
<aop:advisor advice-ref="myBefore" pointcut-ref="pointcut" />
<aop:advisor advice-ref="myAfter" pointcut-ref="pointcut" />
</aop:config>
使用测试:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.add();
userService.update();
userService.delete();
userService.select();
配置aop方式二(自定义类实现):
先自己编写一个类:
public class PointCat {
public void before() {
System.out.println("方法执行前调用.......");
}
public void after() {
System.out.println("方法执行后调用.......");
}
}
然后直接编写配置
<bean id="userService" class="com.huaijiuwang.service.UserServiceImpl" />
<bean id="pointCat" class="com.huaijiuwang.aop.PointCat" />
<aop:config>
<!-- 自定义切面 ref要应用的类 -->
<aop:aspect ref="pointCat">
<!-- 切入点 -->
<aop:pointcut id="pointcut" expression="execution(* com.huaijiuwang.service.UserServiceImpl.*(..))"/>
<!-- 通知 -->
<aop:before method="before" pointcut-ref="pointcut" />
<aop:after method="after" pointcut-ref="pointcut" />
</aop:aspect>
</aop:config>
测试运行:
使用注解方式实现AOP:
使用注解 @Aspect 标识一个类为切面
// 标注类是一个切面
@Aspect
public class AnnotationPointCut {
// 方法执行前
@Before("execution(* com.huaijiuwang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前...........");
}
// 方法执行后
@After("execution(* com.huaijiuwang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后...........");
}
}
编写配置
<!-- 开启注解支持 -->
<bean id="annotationPointCut" class="com.huaijiuwang.aop.AnnotationPointCut" />
<aop:aspectj-autoproxy/>
运行测试:
使用纯配置完成AOP
编写MyConfig配置类
@Configuration // 声明这是个配置类
@ComponentScan("com.huaijiuwang") // 扫描宝,可以使用spring注解
@EnableAspectJAutoProxy // 配置支持aop注解
public class MyConfig {
}
配置aop切面
// 标注类是一个切面
@Aspect
@Component
public class AnnotationPointCut {
// 方法执行前
@Before("execution(* com.huaijiuwang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前...........");
}
// 方法执行后
@After("execution(* com.huaijiuwang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后...........");
}
}
注册service到spring容器中
@Service
public class UserServiceImpl implements UserService{
测试:
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
UserService userServiceImpl = context.getBean("userServiceImpl", UserService.class);
userServiceImpl.add();
导入需要的包:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.23</version> <!-- 选择与Java 8兼容的Spring版本 -->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.23</version>
</dependency>
</dependencies>
1.数据库表创建
-- 创建一个数据库
CREATE DATABASE `mybatis`;
-- 切换到创建的数据库
USE `mybatis`;
-- 创建一张表
CREATE TABLE `user`(
`id` INT NOT NULL PRIMARY KEY,
`name` VARCHAR(20),
`password` VARCHAR(20)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 插入几条数据
INSERT INTO `user`(`id`, `name`, `password`)
VALUES(1, '怀旧', '123456'),
(2, '小旧', '654321'),
(3, '小旧', 'root');
-- 查询当前数据
SELECT * FROM `user`;
2.创建编写需要的.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.huaijiuwang.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&charsetEncoding=UTF-8&serverTimezone=UTC" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
</configuration>
3.编写实体类
@Data
public class User {
private int id;
private String name;
private String password;
}
4.编写接口
public interface UserMapper {
// 查询所有用户
List<User> getUserList();
}
5.注册mapper到xml中
<mappers>
<mapper resource="mapper/UserMapper.xml" />
</mappers>
6.编写Mapper.xml文件
<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.huaijiuwang.mapper.UserMapper">
<select id="getUserList" resultType="com.huaijiuwang.pojo.User">
select * from user
</select>
</mapper>
6.测试运行
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
System.out.println(userMapper.getUserList());
查询数据成功
1.搭建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">
</beans>
2.配置数据库的数据源
<!-- 配置数据源 -->
<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/mybatis?useSSL=true&useUnicode=true&charsetEncoding=UTF-8&serverTimezone=UTC" />
<property name="username" value="root" />
<property name="password" value="123456" />
</bean>
3.配置Mybatis配置
<!-- 配置Mybatis配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
<property name="typeAliases" value="com.huaijiuwang.pojo.User"/>
</bean>
4.配置装载sqlSessionFactory
<!-- 配置Mybatis链接sqlSession -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
5.配置UserMapperImpl类(用来获取数据)
public class UserMapperImpl implements UserMapper{
// 让spring注入,需要的sqlSession对象(就是配置的SqlSessionTemplate对象)
private SqlSessionTemplate sqlSessionTemplate;
// 通过构造方法注入
public UserMapperImpl(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
@Override
public List<User> getUserList() {
// 返回实际的数据(建议写一行就行)
return sqlSessionTemplate.getMapper(UserMapper.class).getUserList();
}
}
6.将UserMapperImpl注册到spring容器
<!-- 注册UserMapperImpl对象 -->
<bean id="userMapper" class="com.huaijiuwang.mapper.UserMapperImpl">
<constructor-arg name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
</bean>
7.测试运行:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
System.out.println(userMapper.getUserList());
优化:
将mybatis的配置区分开,作为一个新的模版,谁都可以套用:
创建一个文件mybatis-spring.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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置数据源 -->
<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/mybatis?useSSL=true&useUnicode=true&charsetEncoding=UTF-8&serverTimezone=UTC" />
<property name="username" value="root" />
<property name="password" value="123456" />
</bean>
<!-- 配置Mybatis配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
<property name="typeAliases" value="com.huaijiuwang.pojo.User"/>
</bean>
<!-- 配置Mybatis链接sqlSession -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
</beans>
在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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 引入mybatis的配置 -->
<import resource="mybatis-spring.xml" />
<!-- 注册UserMapperImpl对象 -->
<bean id="userMapper" class="com.huaijiuwang.mapper.UserMapperImpl">
<constructor-arg name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
</bean>
</beans>
测试运行:
修改实现maper类
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
@Override
public List<User> getUserList() {
return getSqlSession().getMapper(UserMapper.class).getUserList();
}
}
简化配置,
<!-- 配置数据源 -->
<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/mybatis?useSSL=true&useUnicode=true&charsetEncoding=UTF-8&serverTimezone=UTC" />
<property name="username" value="root" />
<property name="password" value="123456" />
</bean>
<!-- 配置Mybatis配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
<property name="typeAliases" value="com.huaijiuwang.pojo.User"/>
</bean>
<!-- 注册UserMapperImpl对象 -->
<bean id="userMapper" class="com.huaijiuwang.mapper.UserMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
从配置文件中,可以看出来我们少了一步获取SqlSessionTemplate步骤
测试运行:
模拟一组需要执行的事务情况,
添加一个用户后立马删除这个用户,需要同时执行:
1.编写接口
// 添加一个用户
int addUser(User user);
// 删除一个用户
int deleteUserById(int id);
2.编写mapper.xml
<insert id="addUser" parameterType="user">
insert into user values(#{id}, #{name}, #{password})
</insert>
<delete id="deleteUserById" parameterType="int">
delete from user where id = #{id}
</delete>
3.实现具体的接口
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
@Override
public List<User> getUserList() {
getSqlSession().getMapper(UserMapper.class).addUser(user)
getSqlSession().getMapper(UserMapper.class).deleteUserById(id)
return getSqlSession().getMapper(UserMapper.class).getUserList();
}
@Override
public int addUser(User user) {
return 0;
}
@Override
public int deleteUserById(int id) {
return 0;
}
}
4.测试:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
userMapper.getUserList().forEach(System.out::println);
添加后完成删除;
现在模拟异常情况:
修改删除语句:
<delete id="deleteUserById" parameterType="int">
delete 1 from user where id = #{id}
</delete>
运行测试:
运行报错,查看数据:
数据被添加进去了,不符合需求,现在就需要使用spring来控制事务了;
1.配置声明式事务
<!-- 配置声明式事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
2.结合aop实现事务的植入
<!-- 结合aop实现事务的植入 -->
<!-- 配置事务的通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给那些方法配置事务 -->
<tx:attributes>
<!-- name:配置事务管理哪一类方法 propagation: 配置事务的传播特性 -->
<tx:method name="add" propagation="REQUIRED" />
<tx:method name="insert" propagation="REQUIRED" />
<!-- * 代表所有方法 -->
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
3.配置事务的切入
<!-- 配置事务的切入 -->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.huaijiuwang.mapper.UserMapperImpl.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
</aop:config>
4.测试(原有的代码没有做任何修改):
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
userMapper.getUserList().forEach(System.out::println);
运行依然报错:
查看数据库数据,没有发生改变,说明事务配置成功!
评论
登录后才可以进行评论哦!