关注公众号
乐享Coding
微信获取PDF版资源,计算机网络图解等更多资源,也可联系我加入学习交流群
Spring 框架两大核心机制(IoC、AOP)
- IoC(控制反转)/ DI(依赖注入)
- AOP(面向切面编程)
Spring 是一个企业级开发框架,是软件设计层面的框架,优势在于可以将应用程序进行分层,开发者可以自主选择组件。
MVC:Struts2、Spring MVC
ORMapping:Hibernate、MyBatis、Spring Data
Spring管理Bean
- 创建对象(反射)
- 依赖注入(属性赋值)set方法或有参构造器
IOC的初步使用
-
创建maven工程,导入jar包依赖。
<dependencies> <!--spring上下文,保存信息--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.8.RELEASE</version> </dependency> <!--lombok简化开发--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> <scope>provided</scope> </dependency> </dependencies>
-
创建实体类Student
@Data public class Student { private int id; private String name; private int age; }
-
通过 IOC 创建对象,在配置文件中添加需要管理的对象,XML 格式的配置文件,文件名可以自定义。
-
Resource文件夹下创建application.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-3.2.xsd ">
<!--配置Student实例对象属性--> <bean id="student" class="com.Long.Entity.Student"> <property name="id" value="1"/> <property name="name" value="张三"/> <property name="age" value="22"/> </bean>
-
-
从 IoC 容器中获取对象,通过 id 获取。
public class Main { public static void main(String[] args) { // 从 IoC 中获取对象,通过 id 获取,加载配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = (Student) applicationContext.getBean("student"); System.out.println(student); } } //打印 Student(id=1, name=张三, age=22)
IOC思想
(1)控制反转,把对象创建和对象之间的调用过程,交给Spring来处理
(2)目的:为了耦合度降低
(3)IOC 底层原理 (singleton下)
-
读取XML配置文件,解析 XML。
-
运用反射机制实例化配置文件中配置所有的 bean(DI)。
(4)设计模式:工厂模式解耦
-
IOC容器底层就是对象工厂(两个接口)
-
BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员使用。加载配置文件时不会创建对象,在获取对象才去创建对象。
-
ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用。加载配置文件时就会在配置文件对象进行创建。
实现类
-
依赖注入(赋值)
XML配置文件方式
无参构造器注入属性值
-
通过配置
<bean>
标签来完成对象的管理。-
id
:对象名。 -
class
:对象的模版类(所有交给 IoC 容器来管理的类必须有无参构造函数,因为 Spring 底层是通过反射机制来创建对象,调用的是无参构造)
-
-
对象的成员变量通过
<property>
标签完成赋值。name
:成员变量名。value
:成员变量值(基本数据类型,String 可以直接赋值,如果是其他引用类型,不能通过 value 赋值)ref
:将 IoC 中的另外一个 bean 赋给当前的成员变量(DI)
<bean id="student" class="com.Long.Entity.Student"> <property name="id" value="1"/> <property name="name" value="张三"/> <property name="age" value="22"/> <property name="address" ref="address"/> </bean> <bean id="address" class="com.Long.Entity.Address"> <property name="value" value="范阳路"/> </bean>`
简化无参构造器配置文件依赖注入(赋值)
p命名空间
xmlns:p="http://www.springframework.org/schema/p"
<bean id="student" class="com.Long.Entity.Student" p:id="1" p:age="22" p:name="张三" p:address-ref="address">
<!-- <property name="id" value="1"/>-->
<!-- <property name="name" value="张三"/>-->
<!-- <property name="age" value="22"/>-->
</bean>
<bean id="address" class="com.Long.Entity.Address" p:value="范阳路">
<!-- <property name="value" value="范阳路"/>-->
</bean>
上述配置无参构造器实现对象的属性值注入底层是调用set方法实现注入的,也可通过有参构造器注入属性值
注意实体类中添加有参构构造器后一定要再写一个无参构造器
有参构造注入属性值
<bean id="student" class="com.Long.Entity.Student">
<constructor-arg index="0" value="1" />
<constructor-arg index="1" value="小肖" />
<constructor-arg index="2" value="18" />
<constructor-arg index="3" ref="address" />
</bean>
<bean id="address" class="com.Long.Entity.Address">
<property name="value" value="范阳路"/>
</bean>
简化有参构造器配置文件依赖注入(赋值)
c命名空间
xmlns:c="http://www.springframework.org/schema/c"
<bean id="student" class="com.Long.Entity.Student" c:id="1" c:age="22" c:name="张三" c:address-ref="address">
<!-- <constructor-arg name="id" value="1" />-->
<!-- <constructor-arg name="name" value="张三" />-->
<!-- <constructor-arg name="age" value="22" />-->
<!-- <constructor-arg name="address" ref="address" />-->
</bean>
<bean id="address" class="com.Long.Entity.Address" c:value="范阳路">
<!-- <constructor-arg name="value" value="范阳路" />-->
</bean>
扩展三种方式:
下标(index)
<constructor-arg index="0" value="小明"></constructor-arg>
类型(type)不建议使用 只能赋值一个参数
<constructor-arg type="java.lang.String" value="小明"></constructor-arg>
参数名(name)
<constructor-arg name="string" value="大雄"></constructor-arg>
通过运行时类获取 bean(创建bean对象)
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); // singleton下
Student student = (Student) applicationContext.getBean(Student.class);// prototype下
System.out.println(student);
这种方式存在一个问题,配置文件中一个数据类型的对象只能有一个实例,否则会抛出异常,因为没有唯一的 bean。
注解实现依赖注入
(1)【概念】代码的特殊标记
(2)【格式】@注解名称(属性名称=属性值,属性名称=属性值…)
(3)【范围】 方法上面,属性上面,类上面
(4)【目的】简化XML文件配置
创建对象
以下四个注解功能都是一样的,不同名字为了表达更清晰
@Component
- 所有类都可以自动创建对象
@Service
- 业务逻辑层
@Controller
- 控制层
@Repository
- Dao持久化数据层
具体使用
-
引入jar包依赖
<!--springAop--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.2.8.RELEASE</version> </dependency>
-
配置文件中开启组件扫描
<?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: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:component-scan base-package="com.Long"/> </beans>
-
类中添加注解
//value属性默认值是首字母小写userService @Component(value = "UserService") // 等于xml中配置<bean id ="UserService",class=...> //只有value属性时也可以这样写@Component("UserService") public class UserService { public void is(){ System.out.println("我是UserService!"); } }
-
测试
@Test public void Test() { // 从 IoC 中获取对象,通过 id 获取,加载配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService UserService = (UserService) applicationContext.getBean("UserService"); UserService.is(); }
组件扫描优化,避免扫描多余组件
<!--开启组件扫描优化,避免扫描不必要组件-->
<context:component-scan base-package="com.Long" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
属性注入
四个注解
注入对象属性,可以调用注入对象方法
@Autowired 根据属性类型进行自动装配
@Qualifier 与@Autowired一起使用,根据名称进行注入,解决Dao接口多个实现类,一般不需要。
@Resource 可以根据类型注入,也可根据名称注入@Resource(name=“{bean的名称}”)
注入普通类型属性,可以给当前对象属性赋值
@Value 注入普通类型(String,int,float…)属性
@Service
public class UserService {
@Resource
private UserService userService;
@Autowired
// @Qualifier("userDaoImpl")
private userDao userDao;
@Value("小红")
private String name;
public void is() {
System.out.println("我是userService");
userDao.add();//增加了一个用户
System.out.println(userService.name); //小红
}
}
完全注解开发(类似Springboot开发)
-
新建Config配置类,添加类注解,脱离XML文件解析配置
@Configuration //当前类作为配置类,替代xml配置文件 @ComponentScan(basePackages = {"com.Long"}) //替代<context:component-scan base-package="com.Long">
-
测试
@Test public void test1(){ ApplicationContext applicationContext= new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = applicationContext.getBean("userService", UserService.class); userService.is(); }
scope 作用域
Spring 管理的 bean 是根据 scope 来生成的,表示 bean 的作用域,共4种,默认值是 singleton。
singleton
:单例,表示通过 IOC 容器获取的 bean 是唯一的,解析配置文件时完成所有Bean创建**【默认】**prototype
:原型,表示通过 IOC 容器获取的 bean 是不同的,getBean()方法时创建对象。request
:请求,表示在一次 HTTP 请求内有效。session
:会话,表示在一个用户会话内有效。
request 和 session 只适用于 Web 项目,大多数情况下,使用单例和原型较多。
(
singleton
,prototype
创建对象的方式不同)Dubeg模式调试可见:
prototype 模式当业务代码获取 IoC 容器中的 bean 时,Spring 才去调用无参构造创建对应的 bean。
singleton 模式无论业务代码是否获取 IoC 容器中的 bean,Spring 在加载 applicationContext.xml 时就会创建 bean。
Spring 的继承
与 Java 的继承不同,Java 是类层面的继承,子类可以继承父类的内部结构信息;Spring 是对象层面的继承,子对象可以继承父对象的属性值。
<bean id="student" class="com.Long.Entity.Student">
<property name="id" value="1"/>
<property name="name" value="张三"/>
<property name="age" value="22"/>
<property name="addressList">
<list>
<ref bean="address"/>
<ref bean="address2"/>
</list>
</property>
</bean>
<bean id="address" class="com.Long.Entity.Address">
<property name="value" value="科技路"/>
</bean>
<bean id="address2" class="com.Long.Entity.Address">
<property name="value" value="范阳路"/>
</bean>
<bean id="stu" class="com.Long.Entity.Student" parent="student"> //继承了student的所有属性值
<property name="name" value="李四"/> //修改了name属性值
</bean>
Spring 的继承关注点在于具体的对象,而不在于类,即不同的两个类的实例化对象可以完成继承,前提是子对象必须包含父对象的所有属性,同时可以在此基础上添加其他的属性。
Spring 的依赖
与继承类似,依赖也是描述 bean 和 bean 之间的一种关系,配置依赖之后,被依赖的 bean 一定先创建,再创建依赖的 bean,student 依赖于 address,无论代码顺序怎样,一定先创建 address,再创建 student。
<bean id="student" class="com.Long.Entity.Student" depends-on="address"/>
<bean id="address" class="com.Long.Entity.Address"/>
bean的创建顺序不会从上到下,而是address一定比student对象先创建。
Bean的生命周期
从对象创建到对象销毁的过程
添加后置处理器有七步(可选),不添加为五步
(1)通过构造器创建bean实例(无参构造)
(2)为bean的属性设置值和对其他bean引用(调用set方法)
(3)把bean实例传递后置处理器的方法
(4)调用bean的初始化方法(需要进行配置初始化方法)
(5)把bean实例传递后置处理器的方法
(6)bean可以使用了(对象获取到了)
(7)当容器关闭时调用bean的销毁方法
- bean对象
public class Student {
private int id;
private String name;
private int age;
private Address address;
public void setId(int id) {
this.id = id;
System.out.println("第二步调用了Set方法");
}
public Student() {
System.out.println("第一步执行了无参构造,创建Student对象");
}
public void initMethod(){
System.out.println("第三步执行了初始化方法");
}
public void destroyMethod(){
System.out.println("第五步执行了销毁方法");
}
}
- xml配置文件
<bean id="student" class="com.Long.Entity.Student" p:id="1" init-method="initMethod" destroy-method="destroyMethod"/>
<!--配置后置处理器-->
<bean id="myBeanPost" class="com.Long.postBean.myPostbean"/>
-
创建后置处理器类,实现BeanPostProcessor接口
-
测试
@Test
public void Test() {
// 从 IoC 中获取对象,通过 id 获取,加载配置文件
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) applicationContext.getBean("student");
System.out.println("第四步获取创建bean对象的实例");
System.out.println(student);
applicationContext.close();
}
AOP
通俗描述:不修改源代码,在主干功能里面添加新功能
底层原理
动态代理
-
有接口情况,使用JDK动态代理
创建接口实现类代理对象,增强类的方法
使用JDK动态代理,使用Proxy类里面的newProxyInstance静态方法创建代理对象
【三个参数】
-
类加载器
-
增强方法所在类,这个类实现的接口,支持多个接口
-
实现接口InvocationHandler,创建对象,写增强逻辑
通过JDK动态代理增强实现类的功能,【不改变源代码!!!】
public class JDKproxy { public static void main(String[] args) { userDaoImpl userDao = new userDaoImpl(); Class[] interfaces ={userDao.class}; userDao Dao =(userDao) Proxy.newProxyInstance(JDKproxy.class.getClassLoader(), interfaces, new ProxyBean(userDao)); int res = Dao.add(1, 2); System.out.println(res); } } class ProxyBean implements InvocationHandler { private Object obj; public ProxyBean(Object obj) { this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //新增功能 System.out.println(method.getName()+"新增了日志功能!参数为"+ Arrays.toString(args)); Object res = method.invoke(obj,args); return res; } }
public class userDaoImpl implements userDao { public int add(int a,int b) { return a+b; }
-
-
没有接口情况,使用CGLIB动态代理
创建子类的代理对象,增强类的方法
术语
- 连接点(可以被增强的方法)
- 切入点(已被实现的增强方法)
- 通知(增强方法的逻辑)
- 切面 (增强方法属于的类)
Spring框架一般都是基于AspectJ实现AOP操作
AspectJ
- 不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用执行AOP操作
基于注解使用
代理类
@Component
@Aspect //生成代理对象
@Order(1) //指定代理顺序,数字越低,优先级越高
public class userProxy {
@Pointcut("execution(* com.Long.Dao.userDao.add(..))")
public void Point(){
}
@Before("Point()") //前置通知
public void before(){
System.out.println("前置通知Before");
}
@After("Point()") //最终通知
public void after(){
System.out.println("最终通知After");
}
@AfterReturning("Point()") //后置通知
public void afterReturning(){
System.out.println("后置通知AfterReturning");
}
@Around("Point()")//环绕通知
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("around环绕通知前");
proceedingJoinPoint.proceed();
System.out.println("around环绕通知后");
}
@AfterThrowing("Point()")
public void AfterThrowing(){
System.out.println("异常通知AfterThrowing");
}
}
实现类
public class userDaoImpl implements userDao {
public void add(int id) {
System.out.println("我是add方法,增加了"+id+"号用户");
}
}
测试
@Test
public void testAOP(){
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("applicationContext.xml") ;
//动态代理的是接口,增强的是实现类bean方法
userDao userDao= (userDao) applicationContext.getBean("userDaoImpl");
userDao.add(2);
}
测试结果
//around环绕通知前
//前置通知Before
//我是add方法,增加了2号用户
//后置通知AfterReturning
//最终通知After
//around环绕通知后
JDBCtemplate
导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!--针对事务相关操作依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!--整合Mybatis等其他框架需要-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
xml配置数据源
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="jdbc:mysql://localhost:3306/bank?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="77549252"/>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
</bean>
<!--配置JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"/>
简单使用
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void addMoney(int money,String name) {
String sql ="update t_account set money=money+? where name =?";
jdbcTemplate.update(sql,money,name);
}
事务
事务是数据库操作的基本单元,逻辑上一组操作,要么都成功,要么都失败。
四个特性(ACID)
(1)原子性
(2)一致性
(3)隔离性
(4)持久性
事务添加到JavaEE三层结构里面Service层(业务逻辑层)
事务管理操作
事务管理API
(1)提供一个PlatformTransactionManager接口,代表事务管理器,这个接口针对不同框架有不同实现类。
声明式事务管理(底层AOP)
(1)注解
-
xml配置文件中配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入dataSource--> <property name="dataSource" ref="dataSource"/> </bean>
-
在spring配置文件,开启事务注解
<!--引入名称空间tx--> xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
<!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"/>
-
在Service类上面或类里面的方法添加事务注解
-
类上面:类中方法都添加事务
-
方法上面:仅该方法添加了事务
@Transactional注解
重要参数
(1)
propagation:事务传播行为
-
多事务方法之间调用,这个过程事务是如何进行管理的。
(2)
isolation:事务隔离级别
-
多事务操作之间不会产生影响。不考虑隔离性产生很多问题。
-
三个读问题
【脏读】:一个未提交事务读取到另一个未提交事务的数据
【不可重复读】:一个未提交事务读取到另一提交事务修改数据。
【虚读】:一个未提交事务读取到另一提交事务添加数据。
-
通过设置事务隔离性,解决读问题
默认未可重复读
(3)
timeout:超时时间
(1)事务需要在一定时间内进行提交,如果不提交就进行回滚。
(2)默认值是-1,设置时间以秒为单位进行计算
(4)
readOnly:是否只读
(1)读:查询操作,写:添加修改删除操作
(2)readOnly 默认值false。表示可以查询,可以添加修改删除操作
(3)设置readOnly值是true,设置成true之后,只能查询
(5)
rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚
(6)
noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚
-
(2)XML配置文件
-
xml配置文件中配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入dataSource--> <property name="dataSource" ref="dataSource"/> </bean>
-
在spring配置文件,开启事务注解
<!--引入名称空间tx--> xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
<!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"/>
-
配置切入点和切面
<!--配置通知--> <tx:advice id="txAdvice"> <tx:attributes> <!--指定哪种规则的方法上面添加事务--> <tx:method name="transferMoney" propagation="REQUIRED"/> <!--<tx:method name="transfer*" propagation="REQUIRED"/> 配置以transfer开头的所有方法--> </tx:attributes> </tx:advice> <!--配置切入点和切面--> <aop:config> <!--配置切入点--> <aop:pointcut id="pt" expression="execution(* com.Long.Service.UserService.*(..))"/> <!--配置切面--> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/> </aop:config>
完全注解开发
新建配置类txconfig
@Configuration //当前类作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.Long"}) //替代<context:component-scan base-package="com
@EnableTransactionManagement //开启事务管理
public class txconfig {
@Bean //配置数据源
public DruidDataSource getDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl("jdbc:mysql://localhost:3306/bank?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC");
druidDataSource.setUsername("root");
druidDataSource.setPassword("77549252");
druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
return druidDataSource;
}
@Bean//配置JdbcTemplate
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource); //建议,到IOC容器中去拿dataSource对象
// jdbcTemplate.setDataSource(getDataSource()); //不建议这样,重复创建对象
return jdbcTemplate;
}
@Bean //配置DataSourceTransactionManager
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
测试:
@Service
@Transactional //声明式事务
public class UserService {
@Autowired
private userDao userDao;
public void transferMoney(){
userDao.addMoney(100,"小肖");
//模拟异常
int error= 1/0;
userDao.reduceMoney(100,"小明");
}
}
@Test
public void testTransactionAnnotation() {
ApplicationContext context = new AnnotationConfigApplicationContext(txconfig.class);
UserService UserService = context.getBean("userService",UserService.class);
UserService.transferMoney();
}
e对象
// jdbcTemplate.setDataSource(getDataSource()); //不建议这样,重复创建对象
return jdbcTemplate;
}
@Bean //配置DataSourceTransactionManager
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
测试:
@Service
@Transactional //声明式事务
public class UserService {
@Autowired
private userDao userDao;
public void transferMoney(){
userDao.addMoney(100,"小肖");
//模拟异常
int error= 1/0;
userDao.reduceMoney(100,"小明");
}
}
@Test
public void testTransactionAnnotation() {
ApplicationContext context = new AnnotationConfigApplicationContext(txconfig.class);
UserService UserService = context.getBean("userService",UserService.class);
UserService.transferMoney();
}