Spring 5(二):IOC容器
概述
IOC(Inversion of Control):控制反转,把对象的创建和对象之间调用的过程交给Spring进行管理
使用IOC的目的:降低耦合度
IOC是一种设计思想,DI(依赖注入)是实现IOC的一种方法
IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
在没有IOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方
实质:获得依赖对象的方式反转了
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式,在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(DI)
底层原理
IOC的底层原理涉及三个技术点:
- xml解析
- 工厂模式
- 反射
引入
假设现在有:
- 一个 Service类
- 一个 Dao接口
- 一个 Dao实现类
interface UserDao {
void add();
}
class UserDaoImpl implements UserDao {
@Override
public void add() {
}
}
class UserService {
public void execute() {
}
}
在 Service类 中,如果我们想要调用 Dao类 中的方法,我们需要实例化 Dao类
class UserService {
private UserDao userDao = new UserDaoImpl();
public void execute() {
userDao.add();
}
}
需求:增加一个新的实现类,客户如何使用
解答:需要到Service中改变userDao变量的类型,这样做每新增加一个类,都需要修改原有的代码
缺点:耦合度太高
这种做法可以达到我们的需求,但如果dao类修改代码,整个程序的代码都需要修改,耦合度太高,为此,,我们需要降低耦合度(高内聚,低耦合)
改进:利用set进行动态实现值的注入
class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void execute() {
userDao.add();
}
}
测试:
public class TestDemo {
public static void main(String[] args) {
UserService service = new UserService();
service.setUserDao(new UserDaoImpl());
service.execute();
}
}
分析
在没有使用set之前,程序主动创建对象,控制权在程序员手上
当利用set注入后,程序不再具有主动性,而是变成了被动的接收对象
例如:新增需求Mysql的实现
只需要扩展一个新类,不需要修改原来代码,用户修改一下用户类就可以调用这个新类
public class TestDemo {
public static void main(String[] args) {
UserService service = new UserService();
service.setUserDao(new UserDaoMysqlImpl());
service.execute();
}
}
工厂模式
为了降低程序的耦合度,我们使用工厂模式来解耦
操作:创建一个工厂类,让工厂来创建对象
public class UserFactory {
public static UserDao getDao() {
return new UserDao();
}
}
现在,如果想要在Service中调用Dao的方法,不需要new一个Dao对象,只需要调用工厂类的getDao方法即可
public class UserService {
private void execute() {
UserDao dao = UserFactory.getDao();
dao.add();
}
}
而我们的最终目的:耦合度降低到最低限制!
IOC解耦
为了进一步降低耦合度,我们使用IOC进行解耦
具体步骤:
- 在maven中导入Spring相关jar包
- 创建实体类
- 创建并配置核心配置文件 applicationContext.xml
- 在Service类中调用Dao方法
- maven配置
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.5</version>
</dependency>
</dependencies>
<bean id="dao" class="com.yue.UserDao"></bean>
接口
通过加载配置文件的方式,Spring提供IOC容器实现两种方式:
- BeanFactory:IOC容器基本实现,是Spring内部使用的接口,一般不提供给开发人员使用
- ApplicationContext:是BeanFactory的子接口,提供了更多、更强大的功能
- 实现类:
- FileSystemXmlApplicationContext:使用全盘符路径
- ClassPathXmlApplicationContext:使用类路径
区别:
- BeanFactory接口在加载配置文件的时候不会创建对象,在获取对象(使用)才去创建对象
- ApplicationContext接口在加载配置文件的时候就会创建配置文件内的对象
Spring配置
别名alias
给bean起别名使用标签 alias
<alias name="user" alias="别名" />
bean标签
bean标签里面的属性有
- id:bean的唯一标识,相当于对象名
- class:bean对象所对应的全限定名(包名+类型)
- name:别名,可以取多个别名,用逗号/分号隔开,也可以用空格分隔;跟id的作用一样,不同的是name中可以加特殊符号,如_
import
导入其他配置文件
<import resource="" />
Bean管理
Bean管理实际指的是两个操作:
- 创建对象
- 依赖注入
Bean管理操作有两种方式:
- 基于 **xml配置文件 **方式实现
- 基于 注解 方式实现
创建对象(xml)
做法:在xml配置文件中,使用bean标签创建对象,标签里面添加对应的属性
<bean id="dao" class="com.yue.UserDao"></bean>
在创建对象的时候,默认执行无参数构造方法
依赖注入(xml)
依赖注入(DI)就是注入属性,DI是IOC的一种具体实现
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的所有属性,由容器来注入
例如:现在实体类User现在有一个属性 : name
public class User {
private String name;
}
实现:在创建对象的过程中,向User的属性name设置一个值
实现方式:
- set注入
- 有参构造方式
- 扩展方式
set注入
set注入方式:在实体类中创建对应的set方法
public class book {
private String name;
public void setName(String name) {
this.name = name;
}
}
在Spring的配置文件中,使用 property标签 对bean属性进行配置
<bean id="book" class="com.yue.pojo.Book">
<!--
使用property完成属性注入
name:类里面属性的名称
value:向属性注入的值
-->
<property name="name" value="易筋经" />
<property name="author" value="达摩" />
</bean>
p名称空间
对于set方法注入的xml文档编写,可以使用p名称空间进行代码的简化
具体使用步骤:
- 现在配置文件中加入p名称空间
xmlns:p="http://www.springframework.org/schema/p"
- 在使用set注入的时候,简写方式为:
<bean id="book" class="com.yue.pojo.Book" p:name="九阳神功" p:author="无名氏"></bean>
构造器注入
实现:在实体类中创建带参数的构造方法
class book {
private String name;
public Book(String name) {
this.name = name;
}
}
在Spring的配置文件中,使用 constructor-arg标签 对bean属性进行配置
<bean id="orders" class="com.yue.pojo.Orders">
<constructor-arg name="name" value="电脑" />
<constructor-arg name="address" value="China" />
</bean>
或者:通过索引值来赋值
<constructor-arg index="0" value="" />
还可以通过参数类型来创建
c命名空间
与p命名空间类似,但必须要有构造器注入
字面量注入
字面量包括:
- null值
- 属性值包含特殊符号
null值的设置
null值得注入使用 null标签
<bean id="book" class="com.yue.pojo.Book">
<property name="name">
<null />
</property>
</bean>
特殊符号
如果想要给属性值设置特殊符号如:<<>>,实现方法有:
- 需要使用转义字符
- 把带特殊符号内容写到CDATA表达式中,CDATA表达式会把内容原样输出
<property name="address">
<value>
<![CDATA[
<<南京>>
]]>
</value>
</property>
bean注入
bean注入得方式:
- 外部bean注入
- 内部bean注入
外部bean
service为一个bean,该bean中有一个dao对象属性,在对service进行bean创建时,需要引入bean之外的bean
- 创建外部bean:dao的实现类
<bean id="userDaoImpl" class="com.yue.dao.UserDaoImpl" />
- 创建本bean,并引入外部bean,使用ref属性引入
<bean id="userService" class="com.yue.service.UserService">
<!--
在service中注入dao
ref属性:创建userDaoImpl对象bean标签的id值
-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
- 测试
@Test
public void TestAdd() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
内部bean
对于引入外部bean的方式,还可以在bean中定义bean
<bean id="userService" class="com.yue.service.UserService">
<property name="userDao">
<bean id="userDaoImpl" class="com.yue.dao.UserDaoImpl"></bean>
</property>
</bean>
级联赋值
级联赋值有两种写法
第一种:与外部bean类似
<bean id="emp" class="com.yue.pojo.Emp">
<property name="name" value="蓝天" />
<property name="gender" value="男" />
<!--设置对象类型属性-->
<property name="dept" ref="dept" />
</bean>
<bean id="dept" class="com.yue.pojo.Dept">
<property name="name" value="巡天" />
</bean>
第二种:这种写法需要在emp中生成dept的 get方法
<bean id="emp" class="com.yue.pojo.Emp">
<property name="name" value="蓝天" />
<property name="gender" value="男" />
<!--设置对象类型属性-->
<property name="dept" ref="dept" />
<property name="dept.name" value="巡查"/>
</bean>
<bean id="dept" class="com.yue.pojo.Dept" />
集合注入
- 注入数组类型
- 注入List集合
- 注入Map集合
- 注入Set集合
- 注入对象集合
现在有一个实体类Student,包含五种集合
public class Course {
private String name;
}
public class Student {
private String[] courses;
private List<String> list;
private Map<String, String> maps;
private Set<String> sets;
private List<Course> courseList;
public void test() {
System.out.println(Arrays.toString(courses));
System.out.println(list);
System.out.println(maps);
System.out.println(sets);
}
}
- 在配置文件中配置
<!--集合类型注入-->
<bean id="student" class="com.yue.pojo.Student" >
<!--数组类型注入-->
<property name="courses">
<array>
<value>语文</value>
<value>数学</value>
<value>英语</value>
</array>
</property>
<!--list类型注入-->
<property name="list">
<list>
<value>张三</value>
<value>李四</value>
</list>
</property>
<!--Map类型注入-->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<!--Set集合注入-->
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>
<!--集合对象注入方式-->
<!--注入list集合类型,值是对象-->
<property name="courseList">
<list>
<ref bean="course1"/>
<ref bean="course2"/>
</list>
</property>
</bean>
<!--创建多个course对象-->
<bean id="course1" class="com.yue.pojo.Course">
<property name="name" value="Spring5框架" />
</bean>
<bean id="course2" class="com.yue.pojo.Course">
<property name="name" value="Mybatis框架" />
</bean>
- 测试
@Test
public void StudentTest() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = context.getBean("student", Student.class);
student.test();
}
提取集合注入部分
使用 util 标签进行注入提取
- 先创建一个Book类
public class Book {
private List<String> list;
public void test() {
System.out.println(list);
}
}
- 在配置文件中引入名称util
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
</beans>
- 使用util标签完成list集合注入提取
<!--提取list集合-->
<util:list id="bookList">
<value>易筋经</value>
<value>九阳神功</value>
<value>九阴真经</value>
</util:list>
<!--注入使用-->
<bean id="book" class="com.yue.pojo.Book">
<property name="list" ref="bookList"/>
</bean>
- 测试
@Test
public void BookTest() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Book book = context.getBean("book", Book.class);
book.test();
}
Properties注入
使用props标签对properties文件的注入
<bean id="book" class="com.yue.pojo.Book">
<property name="info">
<props>
<prop key="">值</prop>
<prop key="">值</prop>
<prop key="">值</prop>
</props>
</property>
</bean>
FactoryBean
Spring有两种类型bean,一种普通bean,另外一种叫工厂bean(FactoryBean)
- 普通bean:在配置文件中,定义的bean类型就是返回类型
- 工厂bean:在配置文件中,定义的bean类型可以和返回的类型不一样
- 创建一个类,让这个类作为工厂bean,实现接口FactoryBean
- 实现接口里面的方法,在实现的方法中定义返回的bean类型
public class MyBean implements FactoryBean<Course> {
//定义返回bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setName("abc");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
<bean id="myBean" class="com.yue.pojo.MyBean"></bean>
@Test
public void MyBeanTest() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Course myBean = context.getBean("myBean", Course.class);
System.out.println(myBean);
}
bean的作用域
在Spring里面,可以设置创建的bean实例是单实例还是多实例
默认情况下,bean是单实例对象
使用 scope标签 设置作用域
scope属性值:
- singleton:默认值
- prototype:多实例对象
- request
- session
- application
- websocket
<bean id="myBean" class="com.yue.pojo.MyBean" scope="prototype" />
测试:
@Test
public void MyBeanTest() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
MyBean myBean = context.getBean("myBean", MyBean.class);
MyBean myBean2 = context.getBean("myBean", MyBean.class);
System.out.println(myBean);
System.out.println(myBean2);
}
输出的两个bean对象是不一样的
singleton与prototype的区别
- singleton单实例,prototype多实例
- singleton:加载spring配置文件的时候就会创建单实例对象
- prototype:不是在加载spring配置文件的时候创建对象,而是在调用getBean方法的时候创建多实例对象
bean的生命周期
生命周期:从对象的创建到对象销毁的过程
bean生命周期:
- 通过构造器创建bean实例(无参数构造)
- 为bean的属性设置值和对其他bean的引用(调用set方法)
- 调用bean的初始化的方法(需要进行配置)
- bean的使用
- 当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)
public class Orders {
private String name;
public Orders() {
System.out.println("第一步、执行无参构造创建bean实例");
}
public void setName(String name) {
this.name = name;
System.out.println("第二步、调用set方法设置属性值");
}
//创建执行的初始化的方法
public void initMethod() {
System.out.println("第三步、执行初始化方法");
}
//创建执行的销毁方法
public void destroyMethod() {
System.out.println("第五步、执行销毁方法");
}
}
<bean id="orders" class="com.yue.pojo.Orders" init-method="initMethod" destroy-method="destroyMethod"/>
@Test
public void OrdersTest() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第四步、获取创建bean实例对象");
System.out.println(orders);
//手动让bean实例销毁
((ClassPathXmlApplicationContext)context).close();
}
后置处理器
bean的生命周期一共有七步:
- 通过构造器创建bean实例(无参数构造)
- 为bean的属性设置值和对其他bean的引用(调用set方法)
- 把bean的实例传递给bean后置处理器的方法 postProcessBeforeInitialization
- 调用bean的初始化的方法(需要进行配置)
- 把bean的实例传递给bean后置处理器的方法 postProcessAfterInitialization
- bean的使用
- 当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)
需要先添加后置处理器,创建一个类,实现接口BeanPostProcessor,实现两个方法
MyBeanPost
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行的方法");
return bean;
}
}
并且需要在配置文件中配置一下
<bean id="myBeanPost" class="com.yue.pojo.MyBeanPost" />
自动装配
在Spring中有三种装配的方式:
- 在xml中显示的配置
- 在Java中显示配置
- 隐式的自动装配bean
手动装配:在创建对象时使用property标签进行依赖注入
自动装配:根据指定配置规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
假设有员工和部门类
class Dept {
}
class Emp {
private String name;
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setName(String name) {
this.name = name;
}
}
bean配置
<bean id="emp" class="com.yue.pojo.Emp" >
<property name="name" value="yue" />
<property name="dept" ref="dept"/>
</bean>
<bean id="dept" class="com.yue.pojo.Dept" />
使用 autowire 完成自动装配
autowire的属性值:
-
byName:根据属性名注入,注入值bean的id值和类属性名称要一样
会自动在容器上下文中查找,和自己对象set方法后面对应的beanid
例如,在emp类中有个Dept属性,并且有setDept方法,会自动在配置文件中找id为dept的bean自动装配
<bean id="emp" class="com.yue.pojo.Emp" autowire="byName" />
<bean id="dept" class="com.yue.pojo.Dept" />
-
byType:根据属性类型注入
会自动在容器上下文中查找,和自己对象属性类型相同的bean
弊端:必须保证类型全局唯一
<bean id="emp" class="com.yue.pojo.Emp" autowire="byType" />
<bean id="dept" class="com.yue.pojo.Dept" />
properties文件引入
把一些固定的、相关的值放到一个其他文件中,然后把文件引入xml文件中
例如:操作数据库时,数据库有一些固定值,把这些固定值放到一个文件中,然后在xml中读取文件中的配置
原始方式:直接在xml中配置数据库信息
- 先引入连接池druid的jar包到maven中
- 在xml配置文件中配置
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" >
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/userDb" />
<property name="username" value="root" />
<property name="password" value="1234" />
</bean>
引入外部属性文件
- 先创建一个外部属性文件,properties格式文件,写入数据库信息
driverClassName= com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/ems?useUnicode=true&characterEncoding=UTF-8&&serverTimezone=GMT
username=root
password=1234
initialSize=5
maxActive=10
maxWait=3000
timeBetweenEvictionRunsMillis=60000
validationQuery=SELECT 1
maxPoolPreparedStatementPerConnectionSize=200
- 把外部properties文件引入到spring配置文件中
- 引入context名称空间
<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:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- 在spring配置文件中使用标签引入外部属性文件
<context:property-placeholder location="druid.properties" />
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" >
<property name="driverClassName" value="${driverClassName}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</bean>
注解
使用注解需要先配置注解的支持,必须保证aop包的导入
<?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:根据 属性类型 进行自动装配
- @Qualifier:根据 属性名称 进行注入
- @Resource:可以根据类型注入,也可以根据名称注入
- @Value:注入普通类型属性
使用注解 @Autowired ,默认byType方式
class Emp {
private String name;
@Autowired
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setName(String name) {
this.name = name;
}
}
<bean id="emp" class="com.yue.pojo.Emp" />
<bean id="dept" class="com.yue.pojo.Dept" />
通过添加这个注解,set方法也可以去掉
class Emp {
private String name;
@Autowired
private Dept dept;
public void setName(String name) {
this.name = name;
}
}
使用注解 @Nullable 说明这个字段可以为null,如
public Emp(@Nullable String name) {
this.name = name;
}
@Autowired有一个默认值:@Autowired(required = true)
如果显示的定义为false,说明这个对象可以为null,否则不允许为空
如果有多个相同的对象,@Autowired识别不了哪个,可以使用注解 @Qualifier 配合使用,例如
class Emp {
private String name;
@Autowired
@Qualifier(value = "dept2")
private Dept dept;
public void setName(String name) {
this.name = name;
}
}
<bean id="dept" class="com.yue.pojo.Dept" />
<bean id="dept2" class="com.yue.pojo.Dept" />
还可以使用注解 @Resource 进行自动装配
该注解会先找名字,如果名字找不到,会找类型,如果有多个类型一致的,会返回错误
可以给该注解添加属性进行精确查找
class Emp {
private String name;
@Resource(name = "dept2")
private Dept dept;
public void setName(String name) {
this.name = name;
}
}
使用 @Value 注解可以注入普通类型
public class UserService {
@Value("abc")
private String name;
}
@Autowired与@Resource的区别:
- 都是用来自动装配的,都可以放在属性字段上
- @Autowired是通过byType方式实现,而且必须要求这个对象存在
- @Resource默认通过byName方式实现,如果找不到名字,则通过byType实现,如果两个都找不到,就报错
- 执行顺序不同
创建对象
使用 @Component 注解来创建bean
@Component
public class Emp {
}
这个bean的默认id为类名的小写
@Component:组件,放在类上,说明这个类被Spring管理了,就是bean
@Component有几个衍生注解,在web开发中,会按照mvc三层架构分层:
- dao:@Repository
- service:@Service
- controller:@Controller
这四个注解,功能一样,都可以创建bean的实例,都是代表将某个类注册到Spring中,装配bean
@Repository
public class UserDao {
}
@Service
public class UserService {
}
@Controller
public class UserController {
}
作用域
作用域的注解为:@Scope
@Scope("singleton") //单例模式
@Scope("prototype") //多例
public class User {
}
组件扫描
除了使用下面开启注解的支持外,还可以使用 component-scan 扫描某些包下面的注解
<context:annotation-config/>
注解扫描:
<context:component-scan base-package="com.yue" />
组件扫描的是整个包下面的类,如何避开某些类不扫描呢?
示例:
<context:component-scan base-package="com.yue" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
- use-default-filters="false":表示现在不使用默认filter,使用自己配置的filter
- context:include-filter:设置扫描哪些内容
这里设置扫描带注解Controller的类
context:exclude-filter:设置哪些内容不进行扫描
<context:component-scan base-package="com.yue" use-default-filters="false">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
完全注解开发
使用注解 @Configuration 完成完全注解开发
自定义一个配置类,例如 SpringConfig,并在类的上面添加注解@Configuration,使之成为一个配置类,替代xml配置文件
@Configuration
@ComponentScan(basePackages = "com.yue")
public class SpringConfig {
//注册一个bean
//方法名字就相当于bean标签的id,返回值就相当于class
@Bean
public User getUser() {
return new User();
}
}
实体类
@Component
public class User {
@Value("lan")
private String name;
}
编写测试类
@Test
public void Test() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
User getUser = context.getBean("getUser", user.class);
System.out.println(getUser.getName());
}