甘肃找人做网站多少钱,网站页面前端基本设计,电子商务网站建设与管理案例,如何被百度收录Bean的存
IoC控制反转#xff0c;就是将对象的控制权交给Spring的IOC容器#xff0c;由IOC容器创建及管理对象。 也就是bean的存储
类注解:五大注解
Controller#xff08;控制器存储#xff09; Service#xff08;服务存储#xff09; Component#xff08;组件存储…
Bean的存
IoC控制反转就是将对象的控制权交给Spring的IOC容器由IOC容器创建及管理对象。 也就是bean的存储
类注解:五大注解
Controller控制器存储 Service服务存储 Component组件存储 Repository仓库存储 Configuration配置存储 五大注解的存的过程都近似一样的,因此,下面我们就只介绍Controller的,其余的类似
Controller控制器存储
使⽤Controller存储bean的代码如下所⽰
Controller // 将对象存储到 Spring 中
public class UserController {public void doController(){System.out.println(do controller);}
}如何观察这个对象已经存在Spring容器当中了呢? 接下来我们学习如何从Spring容器中获取对象
SpringBootApplication
public class SpringIocDemoApplication {public static void main(String[] args) {//获取Spring上下⽂对象ApplicationContext context SpringApplication.run(SpringIocDemoApplicatio//从Spring上下⽂中获取对象UserController userController context.getBean(UserController.class);//使⽤对象userController.doController();}
}ApplicationContext翻译过来就是:Spring上下⽂,因为对象都交给Spring管理了所以获取对象要从Spring中获取那么就得先得到Spring的上下 这个上下⽂,就是指当前的运⾏环境,也可以看作是⼀个容器,容器⾥存了很多内容,这些内容是当前运⾏的环境 观察运⾏结果,发现成功从Spring中获取到Controller对象,并执⾏Controller的doController⽅法 如果把Controller删掉,再观察运⾏结果 报错信息显⽰:找不到类型是:com.example.demo.controller.UserController的bean
获取bean对象的其他⽅式
上述代码是根据类型来查找对象,如果Spring容器中,同⼀个类型存在多个bean的话,怎么来获取呢? ApplicationContext也提供了其他获取bean的⽅式,ApplicationContext获取bean对象的功能,是⽗类BeanFactory提供的功能. 常⽤的是上述1,2,4种,这三种⽅式,获取到的bean是⼀样的 其中1,2种都涉及到根据名称来获取对象.bean的名称是什么呢? Spring bean是Spring框架在运⾏时管理的对象,Spring会给管理的对象起⼀个名字. ⽐如学校管理学⽣,会给每个学⽣分配⼀个学号,根据学号,就可以找到对应的学⽣. Spring也是如此,给每个对象起⼀个名字,根据Bean的名称(BeanId)就可以获取到对应的对象.
Bean的命名约定
我们看下官⽅⽂档的说明:BeanOverview::SpringFramework 程序开发⼈员不需要为bean指定名称(BeanId),如果没有显式的提供名称(BeanId)Spring容器将为该bean⽣成唯⼀的名称. 命名约定使⽤Java标准约定作为实例字段名.也就是说bean名称以⼩写字⺟开头然后使⽤驼峰式⼤⼩写. ⽐如 类名:UserController,Bean的名称为:userController 类名:AccountManager,Bean的名称为:accountManager 类名:AccountService,Bean的名称为:accountService 也有⼀些特殊情况,当有多个字符并且第⼀个和第⼆个字符都是⼤写时,将保留原始的⼤⼩写.这些规则与java.beans.Introspector.decapitalize(Spring在这⾥使⽤的)定义的规则相同. ⽐如 类名:UController,Bean的名称为:UController 类名:AManager,Bean的名称为:AManager 根据这个命名规则,我们来获取Bean ApplicationContext context SpringApplication.run(DemoApplication.class, args);UserController userController context.getBean(UserController.class);userController.doController();System.out.println(userController);UserController userController1 (UserController)context.getBean(userController);userController1.doController();System.out.println(userController1);UserController userController2 context.getBean(userController, UserController.class);userController2.doController();System.out.println(userController2);地址⼀样,说明对象是⼀个 获取bean对象,是⽗类BeanFactory提供的功能 ApplicationContextVSBeanFactory常⻅⾯试题 • 继承关系和功能⽅⾯来说Spring容器有两个顶级的接⼝BeanFactory和 ApplicationContext。其中BeanFactory提供了基础的访问容器的能⼒⽽ ApplicationContext属于BeanFactory的⼦类它除了继承了BeanFactory的所有功能之外它还拥有独特的特性还添加了对国际化⽀持、资源访问⽀持、以及事件传播等⽅⾯的⽀持. • 从性能⽅⾯来说ApplicationContext是⼀次性加载并初始化所有的Bean对象⽽ BeanFactory是需要那个才去加载那个因此更加轻量.(空间换时间)
为什么要这么多类注解
这个也是和咱们前⾯讲的应⽤分层是呼应的.让程序员看到类注解之后就能直接了解当前类的⽤途. • Controller控制层,接收请求,对请求进⾏处理,并进⾏响应. • Servie业务逻辑层,处理具体的业务逻辑. • Repository数据访问层也称为持久层.负责数据访问操作 • Configuration配置层.处理项⽬中的⼀些配置信息. 这和每个省/市都有⾃⼰的⻋牌号是⼀样的. ⻋牌号都是唯⼀的,标识⼀个⻋辆的.但是为什么还需要设置不同的⻋牌开头呢. ⽐如陕西的⻋牌号就是陕XXXXXXX北京的⻋牌号京XXXXXXX甚⾄⼀个省不同的县区也是不同的⽐如西安就是陕AXXXXX咸阳陕BXXXXXX宝鸡陕CXXXXXX⼀样. 这样做的好处除了可以节约号码之外更重要的作⽤是可以直观的标识⼀辆⻋的归属地. 程序的应⽤分层调⽤流程如下 类注解之间的关系 查看 Controller / Service / Repository / Configuration 等注解的源码发 现 其实这些注解⾥⾯都有⼀个注解Component说明它们本⾝就是属于Component 的“⼦类”. Component 是⼀个元注解也就是说可以注解其他类注解如 Controller ,Service ,Repository 等.这些注解被称为 Component 的衍⽣注解. Controller ,Service 和 Repository ⽤于更具体的⽤例(分别在控制层,业务逻辑层,持久化层),在开发过程中,如果你要在业务逻辑层使⽤ Component 或Service显然Service是更好的选择
方法注解:Bean
类注解是添加到某个类上的但是存在两个问题:
使⽤外部包⾥的类,没办法添加类注解⼀个类,需要多个对象,⽐如多个数据源 这种场景,我们就需要使⽤⽅法注解Bean 我们先来看看⽅法注解如何使⽤:
Beanpublic UserInfo userInfo1(){UserInfo userInfo new UserInfo();userInfo.setId(1);userInfo.setAge(26);userInfo.setName(zhangsan);return userInfo;}然⽽当我们写完以上代码尝试获取bean对象中的user时却发现根本获取不到 UserInfo contextBean context.getBean(UserInfo.class);System.out.println(contextBean);这是为什么呢
⽅法注解要配合类注解使⽤
在Spring框架的设计中⽅法注解 Bean 要配合类注解才能将对象正常的存储到Spring容器中 如下代码所⽰ Controller
public class BeanController {Beanpublic UserInfo userInfo1(){UserInfo userInfo new UserInfo();userInfo.setId(1);userInfo.setAge(26);userInfo.setName(zhangsan);return userInfo;}}定义多个对象
对于同⼀个类,如何定义多个对象呢? ⽐如多数据源的场景,类是同⼀个,但是配置不同,指向不同的数据源. 我们看下Bean的使⽤ Beanpublic UserInfo userInfo1(){UserInfo userInfo new UserInfo();userInfo.setId(1);userInfo.setAge(26);userInfo.setName(zhangsan);return userInfo;}Beanpublic UserInfo userInfo2(){UserInfo userInfo new UserInfo();userInfo.setName(lisi);userInfo.setId(2);userInfo.setAge(39);return userInfo;}报错信息显⽰:期望只有⼀个匹配,结果发现了两个,user1,user2 从报错信息中,可以看出来,Bean注解的bean,bean的名称就是它的⽅法名 接下来我们根据名称来获取bean对象 UserInfo userInfo1 (UserInfo)context.getBean(userInfo1);System.out.println(userInfo1);UserInfo userInfo2 (UserInfo)context.getBean(userInfo2);System.out.println(userInfo2);重命名 Bean
可以通过设置name属性给Bean对象进⾏重命名操作如下代码所⽰: Bean(name {u1,userInfo1})public UserInfo userInfo1(){UserInfo userInfo new UserInfo();userInfo.setId(1);userInfo.setAge(26);userInfo.setName(zhangsan);return userInfo;}Bean(name {u2, userInfo2})public UserInfo userInfo2(){UserInfo userInfo new UserInfo();userInfo.setName(lisi);userInfo.setId(2);userInfo.setAge(39);return userInfo;}UserInfo userInfo1 (UserInfo)context.getBean(u1);System.out.println(userInfo1);UserInfo userInfo2 (UserInfo)context.getBean(u2);System.out.println(userInfo2);name{}可以省略如下代码所⽰ Bean({u1,userInfo1})
只有⼀个名称时,{}也可以省略,如: Bean(u1)
注意:类注解的五大注解也可以使用该方法进行重命名操作
Bean的取
上⾯我们讲解了控制反转IoC的细节接下来呢我们学习依赖注⼊DI的细节,依赖注⼊是⼀个过程是指IoC容器在创建Bean时,去提供运⾏时所依赖的资源⽽资源指的就是对象.简单来说,就是把对象取出来放到某个类的属性中.在⼀些⽂章中,依赖注⼊也被称之为对象注⼊,“属性装配”,具体含义需要结合⽂章的上下⽂来理解 关于依赖注⼊,Spring也给我们提供了三种⽅式:
属性注⼊(Field Injection)构造⽅法注⼊(Constructor Injection)Setter注⼊(Setter Injection)接下来我们分别来看。 下⾯我们按照实际开发中的模式将Service类注⼊到Controller类中
属性注⼊
属性注⼊是使⽤Autowired实现的将Service类注⼊到Controller类中。 Service类的实现代码如下:
Service
public class UserService {public void doService(){System.out.println(do service);}
}Controller类的实现代码如下
Controller
public class UserController {Autowiredprivate UserService userService;public void doController(){userService.doService();System.out.println(do controller);}
}获取Controller中的doController⽅法
ApplicationContext context SpringApplication.run(DemoApplication.class, args);UserController userController context.getBean(UserController.class);userController.doController();去掉Autowired,再运⾏⼀下程序看看结果
构造⽅法注⼊
Controller
public class UserController {
// Autowiredprivate UserService userService;public UserController(UserService userService) {this.userService userService;}public void doController(){userService.doService();System.out.println(do controller);}
}注意事项如果类只有⼀个构造⽅法那么Autowired注解可以省略如果类中有多个构造⽅法 那么需要添加上Autowired来明确指定到底使⽤哪个构造⽅法
Controller
public class UserController {
// Autowiredprivate UserService userService;public UserController() {}public UserController(UserService userService) {this.userService userService;}public void doController(){userService.doService();System.out.println(do controller);}
} Controller
public class UserController {
// Autowiredprivate UserService userService;public UserController() {}
Autowiredpublic UserController(UserService userService) {this.userService userService;}public void doController(){userService.doService();System.out.println(do controller);}
} Setter注⼊
Setter注⼊和属性的Setter⽅法实现类似只不过在设置set⽅法的时候需要加上Autowired注解如下代码所⽰:
Controller
public class UserController {
// Autowiredprivate UserService userService;
Autowiredpublic void setUserService(UserService userService) {this.userService userService;}public void doController(){userService.doService();System.out.println(do controller);}
} 三种注⼊优缺点分析
属性注⼊ ◦ 优点:简洁使⽤⽅便 ◦ 缺点: ▪ 1.只能⽤于IoC容器如果是⾮IoC容器不可⽤并且只有在使⽤的时候才会出现NPE空指针异常 ▪ 不能注⼊⼀个Final修饰的属性 • 构造函数注⼊(Spring4.X推荐) ◦ 优点: ▪ 1.可以注⼊final修饰的属性 ▪ 2.注⼊的对象不会被修改 ▪ 3.依赖对象在使⽤前⼀定会被完全初始化因为依赖是在类的构造⽅法中执⾏的⽽构造⽅法是在类加载阶段就会执⾏的⽅法。 ▪ 4.通⽤性好,构造⽅法是JDK⽀持的,所以更换任何框架,他都是适⽤的 ◦ 缺点: ▪ 注⼊多个对象时,代码会⽐较繁琐 • Setter注⼊(Spring3.X推荐) ◦ 优点:⽅便在类实例之后,重新对该对象进⾏配置或者注⼊ ◦ 缺点: ▪ 1.不能注⼊⼀个Final修饰的属性 ▪ 2.注⼊对象可能会被改变,因为setter⽅法可能会被多次调⽤,就有被修改的⻛险 更多DI相关内容参考:Dependencies :: Spring Framework
Autowired存在问题
当同⼀类型存在多个bean时,使⽤Autowired会存在问题 Bean(u1)public UserInfo userInfo1(){UserInfo userInfo new UserInfo();userInfo.setId(1);userInfo.setAge(26);userInfo.setName(zhangsan);return userInfo;}Bean(name {u2, userInfo2})public UserInfo userInfo2(){UserInfo userInfo new UserInfo();userInfo.setName(lisi);userInfo.setId(2);userInfo.setAge(39);return userInfo;}Controller
public class UserController {
// Autowiredprivate UserService userService;Autowiredpublic void setUserService(UserService userService) {this.userService userService;}Autowiredprivate UserInfo userInfo;public void doController(){userService.doService();System.out.println(do controller);System.out.println(userInfo);}
}如何解决上述问题呢Spring提供了以下⼏种解决⽅案
Primary
使⽤Primary注解当存在多个相同类型的Bean注⼊时加上Primary注解来确定默认的实现 PrimaryBean(u1)public UserInfo userInfo1(){UserInfo userInfo new UserInfo();userInfo.setId(1);userInfo.setAge(26);userInfo.setName(zhangsan);return userInfo;}Qualifier
使⽤Qualifier注解指定当前要注⼊的bean对象。在Qualifier的value属性中指定注⼊的bean的名称 Qualifier注解不能单独使⽤必须配合Autowired使⽤
Controller
public class UserController {
// Autowiredprivate UserService userService;Autowiredpublic void setUserService(UserService userService) {this.userService userService;}Qualifier(u2)Autowiredprivate UserInfo userInfo;public void doController(){userService.doService();System.out.println(do controller);System.out.println(userInfo);}
}Resource
使⽤Resource注解是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称
Controller
public class UserController {
// Autowiredprivate UserService userService;Autowiredpublic void setUserService(UserService userService) {this.userService userService;}
// Qualifier(u2)
// AutowiredResource(name u1)private UserInfo userInfo;public void doController(){userService.doService();System.out.println(do controller);System.out.println(userInfo);}
} ⾯试题Autowird与Resource的区别 • Autowired是spring框架提供的注解⽽Resource是JDK提供的注解 • Autowired默认是按照类型注⼊⽽Resource是按照名称注⼊ Autowired和Resource的区别 • Autowired来⾃于Spring⽽Resource来⾃于JDK的注解 • 使⽤时设置的参数不同相⽐于Autowired来说Resource⽀持更多的参数设置例如name设置根据名称获取Bean
bean的命名
1)五⼤注解存储的bean ①前两位字⺟均为⼤写,bean名称为类名 ②其他的为类名⾸字⺟⼩写 ③通过value属性设置 Controller(value “user”) 2)Bean注解存储的bean ①bean名称为⽅法名 ②通过name属性设置 Bean(name {“u1”,“user1”})