文章目录
- 一、Spring
- 1.1、概述
- 1.3、IOC(控制反转)
- 1.3.1、IOC实现原理
- 1.4、Spring创建对象的方法
- 1.4.1、一般创建(无参构造)
- 1.4.2、静态工厂创建
- 1.4.3、实例工厂创建
- 1.4.4、Spring工厂创建
- 1.5、单例和多例
- 1.6、依赖注入
- 二、Spring注解方式实现IOC和DI
- 2.1、自定义注解
- 2.2、反射注解
- 2.3、Spring注解IOC
- 2.4、Spring注解DI
- 2.5、其他注解
一、Spring
1.1、概述
Spring是一个Service层框架,可以整合其它许多框架。
Spring的主要技术:
- IOC(DI):控制反转(依赖注入)
- AOP:面向切面编程
1.3、IOC(控制反转)
将对象的创建和及对象的生命周期管理过程交给Spring框架来处理,开发过程不再关注对象的的创建和生命周期的管理。
创建过程中Spring可以根据配置对象属性进行设置,这个过程也叫做依赖注入,即DI。
1.3.1、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">
<bean id="spring_helloworld01" class="main.Spring_helloworld01"></bean>
</beans>
- 初始化Spring容器: Spring会解析指定的xml文件,当解析到其中的标签时会根据标签中的class属性指定类的全路径名,通过反射创建改类的对象,并将该对象存入内置的Map中管理。之中键就是id标签,值就是该对象
- 从容器中获取对象: 根据传入的条件在内置的Map中寻找匹配的键值,如果有则将该键值中保存的对象返回,没有则抛出异常。
推论:
(1)多次获取同一个id的bean,得到的是同一个对象;
(2)同一个类对应不同id,都会在内置Map中有一个键值对,即创建不同对象;
(3)同一个标签不允许配置多个同id的标签。
1.4、Spring创建对象的方法
1.4.1、一般创建(无参构造)
public class Spring_helloworld01 {
public void eat(){
System.out.println("eat");
}
public void say(){
System.out.println("say");
}
}
<?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="spring_helloworld01" class="main.Spring_helloworld01"></bean>
</beans>
实例:
//1、初始化spring容器
ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
//2、通过容器获取Bean
Spring_helloworld01 shello=(Spring_helloworld01)context.getBean("spring_helloworld01");
shello.eat();
shello.say();
1.4.2、静态工厂创建
public class Spring_helloworld01 {
public static Calendar getcalendar(){
return Calendar.getInstance();
}
}
<?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="calender" class="main.Spring_helloworld01" factory-method="getcalendar"></bean>
</beans>
实例:
// 1、初始化spring容器
ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
//2、获取bean
Calendar cal=(Calendar)context.getBean("calender");
System.out.println(cal.toString());
1.4.3、实例工厂创建
public class CalendarFactory {
public CalendarFactory(String name){}
public Calendar getCalendar(){
return Calendar.getInstance();
}
}
public class Spring_helloworld01 {
public CalendarFactory getInstance(){
return new CalendarFactory("test");
}
}
<?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="helloInstanceFactory" class="main.Spring_helloworld01" ></bean>
<bean id="hello1" factory-bean="helloInstanceFactory" factory-method="getInstance"></bean>
</beans>
实例:
// 1、初始化spring容器
ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
//2、获取bean
CalendarFactory cal=(CalendarFactory)context.getBean("hello1");
System.out.println(cal.getCalendar());
1.4.4、Spring工厂创建
public class CalendarSpringFactory implements FactoryBean<Calendar> {
/**
* 产生Bean的方法
* @return
* @throws Exception
*/
@Override
public Calendar getObject() throws Exception {
return Calendar.getInstance();
}
/**
* 获取Bean类型的方法
* @return
*/
@Override
public Class<?> getObjectType() {
return Calendar.class;
}
/**
* 当前Bean的创建模式:单例或多例
* @return
*/
@Override
public boolean isSingleton() {
return true;
}
}
<?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">
<!--Spring工厂-->
<bean id="springfac" class="main.CalendarSpringFactory"></bean>
</beans>
实例:
// 1、初始化spring容器
ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
//2、获取bean
Calendar cal=(Calendar)context.getBean("springfac");
System.out.println(cal);
1.5、单例和多例
Spring容器管理的Bean默认情况下是单例,即,一个bean创建的对象存在内置map中,无论获取多少次该Bean,返回都是同一个对象。
单例可以减少对象创建,从而减少内存消耗。实际开发中也存在多例的需求,可以将bean设置为多例。
区别:
懒加载配置方式: lazy-init
懒加载机制只对单例有用,对于多例没有意义。
<bean id="sp" class="main.SigletonAndPropoty" scope="singleton" lazy-init="true"></bean>
1.6、依赖注入
在对象创建过程中,Spring根据配置对对象属性进行设置,这个过程叫做依赖注入(DI).
方式一: set方法
public class DI {
private String name;
private int age;
private List<String> jobs;
private Set<String> skills;
private Map<String,String> map;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getJobs() {
return jobs;
}
public void setJobs(List<String> jobs) {
this.jobs = jobs;
}
public Set<String> getSkills() {
return skills;
}
public void setSkills(Set<String> skills) {
this.skills = skills;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
@Override
public String toString() {
return "name:"+name+"\nage:"+age+"\njobs:"+jobs+"\nskills:"+skills+"\nmap:"+map;
}
}
<?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">
<!--依赖注入-->
<!--seter方式-->
<bean id="di" class="main.DI">
<property name="name" value="jin"></property>
<property name="age" value="28"></property>
<property name="jobs">
<list>
<value>读书</value>
<value>写字</value>
</list>
</property>
<property name="skills">
<set>
<value>s1</value>
<value>s2</value>
</set>
</property>
<property name="map">
<map>
<entry key="k1" value="v1"></entry>
<entry key="k2" value="v2"></entry>
</map>
</property>
</bean>
</beans>
实例:
// 1、初始化spring容器
ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
//2、获取bean
DI cal=(DI)context.getBean("di");
System.out.println(cal);
自定义类型的注入:
private Dog dog;
class Dog{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Dog{name:"+name+", age:"+age+"}";
}
}
<property name="dog" ref="dog"></property>
<bean id="dog" class="main.Dog">
<property name="name" value="旺财"></property>
<property name="age" value="5"></property>
</bean>
方式二: 自动装配方法
标签:autowire
- byName
Spring会自动根据bean属性的名称找对应id的bean进行属性注入。要求bean的id和bean的属性名称一致。 - byType
Spring会根据bean的属性类型找对应class类型的bean属性注入。要求bean的class类型和bean属性类型一致。
这个类型的bean只有一个,如果有多个会抛异常。
例子:
autowire="byName"
autowire="byType"
方式三:构造方法
public class DI {
private String name;
private int age;
private List<String> jobs;
private Set<String> skills;
private Map<String,String> map;
DI(String name,int age,List<String> jobs,Set<String> skills,Map<String,String> map){
this.name=name;
this.age=age;
this.jobs=jobs;
this.skills=skills;
this.map=map;
}
}
<?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="di1" class="main.DI">
<constructor-arg index="0" type="java.lang.String" value="jin"></constructor-arg>
<constructor-arg index="1" type="int" value="28"></constructor-arg>
<constructor-arg index="2" >
<list>
<value>读书</value>
<value>写字</value>
</list>
</constructor-arg>
<constructor-arg index="3" >
<set>
<value>s1</value>
<value>s2</value>
</set>
</constructor-arg>
<constructor-arg index="4" >
<map>
<entry key="k1" value="v1"></entry>
<entry key="k2" value="v2"></entry>
</map>
</constructor-arg>
</bean>
</beans>
实例:
// 1、初始化spring容器
ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
//2、获取bean
DI cal=(DI)context.getBean("di1");
System.out.println(cal);
二、Spring注解方式实现IOC和DI
2.1、自定义注解
类似于接口,可以通过@interface声明一个注解。可以通过元注解修饰注解的另一控制自定义注解的特征。
元注解:
- @target:声明当前定义的注解可以使用的位置。可以在元注解中声明
ElementType
类型的参数来指定注解使用的位置 - @Retention:声明当前定义的注解会被保留到什么阶段。可以在
RetentionPolicy
类型的参数来指定阶段
-
RetentionPolicy.SOURCE
:源码阶段,编译过程丢弃 -
RetentionPolicy.CLASS
:注解保留在源码和编译阶段,在类加载过程中被删除 -
RetentionPolicy.RUNTIME
:注解保留在源码、编译和运行阶段
- @Documented:指定当前注解是否会被文档提取工具提取到自动生成的文档中。
- @Inherited:被修饰的注解是否具有继承性,默认没有继承性
在注解中声明属性的过程类似于接口中定义方法。在注解声明中定义的属性需要在使用注解时为属性赋值(在小括号内通过“属性名=属性值”进行,多个属性可以使用逗号隔开)。声明的属性必须为public(默认为public)。声明的属性类型必须为:八大基本类型、String、class、枚举、其它注解、以上类型一维数组类型。
在注解声明中定义属性时可以后跟default关键字指定默认值。
如果注解中只有一个属性值需要被赋值且该属性名叫做value
,则value=
可以不写。
如果注解的属性为数组类型,且数组只有一个值,则包裹数组的{}
可以不写。
2.2、反射注解
/**
* 反射注解
*/
public class NoteDemo {
public static void main(String[] args) {
Police.fakuan();
if(Police.class.isAnnotationPresent(Level.class)){
Level level=Police.class.getAnnotation(Level.class);
if("辅警".equals(level.value())){
System.out.println("少罚点....");
}else if("交警".equals(level.value())){
System.out.println("罚200....");
}else if("刑警警".equals(level.value())){
System.out.println("罚500....");
}else{
System.out.println("交钱....");
}
}else{
System.out.println("假警察....");
}
}
}
/**
* 自定义注解
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Level{
String value() default "交警";
}
@Level("辅警")
class Police{
public static void fakuan(){
System.out.println("罚款....");
}
}
2.3、Spring注解IOC
这种方式效率高,配置清晰、修改方便,推荐使用。所谓注解,就是给程序看的提示信息,很多时候作为轻量级的配置方式。
- 开启包扫描
<context:component-scan base-package="main"></context:component-scan>
- 使用注解注册bean
在配置的包中的类上使用@Component
注解,这个类自动被注册为bean,使用当前类的class的为的class,通常情况下使用类名首字母的小写为id。
例子:
@Component
public class Person {
}
**bean的id:**通常情况下注解注册的bean使用类名首字母小写为bean的id,但是如果类名第二个字母为大写则首字母保留原样。
也可以通过
@Component
的value指定id
2.4、Spring注解DI
- 开启注解方式注入
<context:annotation-config></context:annotation-config>
- 使用注解依赖注入(DI)
@Component("pson")
public class Person {
//普通变量的注入
@Value("jin")
private String name;
@Value("15")
private int age;
//集合类型的依赖注入
@Value("#{@l1}")
private List<String> jobs;
@Value("#{@s1}")
private Set<String> skills;
@Value("#{@m1}")
private Map<String,String> map;
@Override
public String toString() {
return "name:"+name+"\nage:"+age+"\njobs:"+jobs+"\nskills:"+skills+"\nmap:"+map;
}
}
注意:可以通过设置@Component中的Value值自定义bean的id值
集合类型的依赖注入配置:
<!--配置集合数据-->
<util:list id="l1">
<value>play</value>
<value>eat</value>
</util:list>
<util:set id="s1">
<value>compute</value>
<value>iphon</value>
</util:set>
<util:map id="m1">
<entry key="k1" value="v1"></entry>
<entry key="k2" value="v2"></entry>
</util:map>
补充:外部配置文件依赖注入
- 加载外部属性配置文件
<context:property-placeholder location="classpath:/db.properties"></context:property-placeholder>
- 使用注释依赖注入
@Component
public class MysqlConnector {
@Value("${dirverName}")
private String dirverName;
@Value("${url}")
private String url;
@Value("${name}")
private String name;
@Value("${password}")
private String password;
@Override
public String toString() {
return "dirverName:"+dirverName+"\nurl:"+url+"\nname:"+name+"\npassword:"+password;
}
}
db.properties
文件:
dirverName=com.sql.jbdc.Driver
url=jdbc:mysql://SpringDB
name=root
password=root
2.5、其他注解
- **@Scope:**单例/多例设置
-
ConfigurableBeanFactory.SCOPE_PROTOTYPE
:多例 -
ConfigurableBeanFactory.SCOPE_SINGLETON
:单例
默认情况下为单例。
@Lazy
:设置单例为懒加载
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)//多例
@Lazy
public class OtherPerson {
public void eat(){
System.out.println("吃。。。");
}
}
- @PostConstruct和 @PreDestroy
@PostConstruct
:初始化方法
@PreDestroy:
:销毁方法
@Component
public class OtherPerson {
public void eat(){
System.out.println("吃。。。");
}
@PostConstruct
public void Init(){
System.out.println("初始化。。。");
}
@PreDestroy
public void Destroy(){
System.out.println("销毁。。。");
}
}
- @Controller、@Service、@Repository和@Component:修饰类声明为Spring管理的bean
@Controller
:web层
@Service
:服务器层
@Repository
:数据访问层
@Component:
:通用