1)@Autowired实现根据name再根据类型,@Resource则相反,先根据类型,再根据name
2)Bean的作用域在Spring容器里面默认是单例模式
1)我们先写一段代码:
package APP.Service; import APP.BeanMethod.User; import org.springframework.stereotype.Service; @Service public class UserService { public void start(String name) { System.out.println("我是Service" + name); } @Bean(name="u1") public User run(Integer id) {//前端传过来的参数可能是空,根据用户ID查询数据库; if (id == 1) { User user = new User(); user.setId(id); user.setName("周韵杠"); return user; }else{ User user=new User(); user.setName("胡子"); user.setId(id); return user; } } }2)我们再写一个类用于获取id为1的user对象
@Controller public class UserController { @Resource(name="u1") private User user; public User GetUser() { User user1=user;//创建一个新的引用 user.setName("曹操"); return user; } }3)我们再写一个类在用来获取id为1的user对象
@Controller public class JavaController { @Autowired private User u1; public User GetUser() { User user=u1; return user; } }4)main方法的函数
ApplicationContext context=new ClassPathXmlApplicationContext("web.xml"); UserController userController=context.getBean("userController",UserController.class); JavaController javaController=context.getBean("javaController",JavaController.class); User user1=userController.GetUser(); User user2=javaController.GetUser(); System.out.println(user1); System.out.println(user2); 此时打印出的结果是:User{id=1, name='曹操'}
User{id=1, name='曹操'}
但是我们发现,user2不是应该打印周韵杠吗?
什么是作用域:限定程序中变量的可用范围就叫做作用域,或者在源代码中定义变量的某个区域就叫做作用域,有几种类型;
但是Bean的作用域是指Bean在整个Spring框架容器里面的某种行为模式,是Bean的类型有哪些 ,比如说singLeton单例作用域,就表示Bean在整个Spring框架里面只有一份,他是全局共享的,那么当其他人修改了这个值之后,那么另一个人读到的就是被修改的值
Spring容器在进行初始化一个Bean的实例的时候,同时会指定该实例的作用域,Spring有六种作用域,最后四种是针对SpringMVC生效的
因为单例模式只被初始化一次,初始化一次之后我们可以反复的进行使用,所以使用的性能比较高,所有人都是用的一个对象;
web项目:通过浏览器或者postman的方式来进行访问一个地址的方式来进行发送Http请求,与咱们的在idea中的Spring代码进行交互,是具有上面的5种值;
1.singleton:单例模式
描述:该作用域下的Bean在IOC容器中只存在一个实例:
当我们进行获取Bean(即通过applicationContext.getBean等方法获取以及装配Bean(即通过Autowired注入)这都是一个对象;
场景:通常无状态的Bean的使用该作用域,无状态表示Bean对象的属性状态不需要进行更新,不会修改Bean,通常我们的Spring默认选择该作用域;
缺点:一个改变了,其他的就都改变了;
2.prototype:原型模式
描述:每次对于该作用域下面的Bean的请求都会创建新的实例:当我们进行获取Bean的时候(即通过applicationContext.getBean()方法来进行获取)或者装配Bean(即通过Autowired来进行注入),这几种方法获取的都是新的对象实例,每一个类中引入的对象都是自己的;
场景:通常有状态的Bean使用该作用域
3.Request
描述:每一次HTTP请求都会创建新的Bean实例,就类似于prototype
场景:一次http请求和响应的共享Bean
备注:只限于SpringMVC中使用,在咱们的普通项目是不能进行使用的
4.session
描述:在一个HttpSession中,定义一个Bean实例
场景:用户会话的共享Bean,比如说记录一个用户的登录信息,是针对一个人来进行操作的,只要是这个人操作的,就会对应到这个实例;
备注:只是限于SpringMVC中进行使用
5.application
描述:在一个http servlet context中对应一个Bean实例
场景:Web应用的上下文信息,比如说记录一个应用的共享信息
备注:只限于SpringMVC进行使用
singletion是作用于整个Spring(IOC容器)容器当中,application是在一个Servlet容器当中(处理WEB请求)
6.WebSocket
描述:在一个Http WebSocket的生命周期中,定义一个Bean实例
场景:WebSocket的每一次对话当中,保存了一个Map结构的头信息,将来用于包裹客户端消息头,第一次初始化之后,直到WebSocket结束都是同一个Bean
备注:限定在Spring WebSocket中使用
单例作用域和全局作用域
singletion是Spring Core的作用域,application是Spring Web的作用域(只有在Servlet里面,在SpringMVC里面才有效果的)
singletion是作用域IOC的容器,而application是作用于Servlet的容器
1)直接使用@Scope他是可以即应用于类注解上面,又能应用于方法注解上面
@Scope("prototype")直接去设置相应的值
2)直接使用枚举进行设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
3)Scope翻译成中文是作用域的意思,虽然说@Scope是可以进行应用到类注解和方法注解,但是如果应用到类注解,就说明进行设置当前这个类所生效;
4)我们一定要注意,我们如果想要方法的返回值是单例的或者是多例的,我们就可以经这个注解修饰方法,如果我们要使用的是@Bean注解·+@Scope,@Scope一定要放在方法上进行注解,不能放在类上;
@Component public class GetBean { @Bean(name ="u1")//将当前User对象存储到Spring里面 @Scope("prototype") public User GetUser1(){ User user=new User(); user.setId(1); user.setName("李佳伟"); return user; }
5)其他需要使用Bean对象的地方就可以直接进行获取并使用了
6)执行完之后,执行销毁操作
Bean的执行流程(Spring的执行流程)-----启动Spring容器-----实例化Bean(分配内存空间,从无到有)-----将Bean进行注册到Spring里面(存储操作)-----我们最后再将Bean装配到需要的类中,取操作;
所谓的生命周期就是指一个对象从创建到销毁的整个过程
1)实例化Bean,为Bean对象分配内存空间
2)进行设置它的属性(Bean的注入和装配)
我们一定是要先进行加载属性的,如果先进行初始化方法,很有可能就会在方法里面用到这个类属性(如果这个属性被@Resource或者Autowired所修饰,那么我们就需要对使用的Bean进行初始化注入)
一个类是有属性和方法的
3)(Bean初始化---一系列准备工作的统称),执行各种通知方法,比如说在飞机上进行检查工作,检查按钮;
3.1实现了各种Aware通知的方法,比如说BeanNameAware,BeanFactory,ApplicationContextAware的接口方法
3.2执行BeanPostProcessor初始化前置方法,如果有的话,就执行,前两种是系统级别的
3.3执行带注解的@PostConstruct初始化方法,依赖注入操作之后进行执行
是否为InitializingBean调用afterPropertiesSet方法
3.4执行自己所指定的init-method方法,如果有指定的话(最早使用XML的方式,在没有注解之前)
3.5执行BeanPostProcess初始化后置方法
4)使用Bean
5)进行销毁Bean
5.1首先会执行@PreDestory这是销毁前方法,比如说像记录一下时间,日志
5.2如果说实现了DisposableBean接口方法
5.3destory-method:销毁前的执行方法,在XML里面进行设置
下面我们写了一些代码来进行演示:
@Controller public class UserController implements BeanNameAware { @Resource private UserService userService; public UserController(UserService userService) { this.userService = userService; } @Override public void setBeanName(String s) { System.out.println("执行通知方法"+s); } @PostConstruct//出生于注解时代 public void start() { System.out.println("执行被注解@PostConstruct修饰的方法"); } public void init()//直接这么写,是无法进行执行的,我们必须要在XML里面进行相应的配置,这里面的方法名字是可以随便取的,只要和XML里面的名字相匹配就可以了 { System.out.println("执行init方法"); } public void destory() { System.out.println("执行destory方法"); } @PreDestroy public void predestory() { System.out.println("执行被注解修饰的"); } }class HelloServlet{ public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("web.xml"); UserController userController=context.getBean("userController",UserController.class); userController.destory(); } }
web.xml配置文件:
打印结果:执行通知方法userController
执行被注解@PostConstruct修饰的方法
执行通知方法userinit
执行被注解@PostConstruct修饰的方法
执行init方法
执行destory方法