Spring

25 篇文章 0 订阅
19 篇文章 0 订阅

今天将学习三大框架的Spring!

Spring

spring是一个开源框架,为了解决企业应用开发的复杂性而创建,但是现在已经不仅应用于企业应用。是一个轻量级的控制反转(Ioc)和面向切面(Aop)的容器框架。

  • 从大小与开销两方面是轻量级。
  • 通过控制反转(Ioc)来达到松耦合的目的。
  • 提供了面向切面编程的支持,允许通过分离应用的业务逻辑与系统级服务进行内聚性开发。
  • 包含并管理应用对象的配置和生命周期,这个意义上是个容器。
  • 将简单的组件,配置成复杂的应用,这就是框架。

面向接口编程

  1. 结构设计中,分清层次及调用关系,每层只向外(上层)提供一组功能接口,各层间仅依赖接口而非实现类。
  2. 接口实现的变动,不影响各层的调动。
  3. 面向接口编程, “接口”是隐藏具体实现和实现多态性的组件。

面向接口编程小例子

public interface TestInterface {
	void show(String word);

}
public class TestInterfaceImpl implements TestInterface{

	@Override
	public void show(String word) {
		// TODO Auto-generated method stub
		System.out.println(word);
		
	}

}
public static void main(String[] args) {
			TestInterface ti = new TestInterfaceImpl();
			ti.show("66666666666");
		}

Ioc

控制反转,控制权转移,应用程序不依赖对象的创建和维护,而是由外部容器负责创建和维护。DI(依赖注入)是实现方式的一种,目的是创建对象和组建对象的关系。

Sping注入

spring注入是指在启动Spring容器加载bean配置的时候,完成对变量的赋值行为。
常用注入方式

  1. 设值注入(Ioc容器使用属性的setter方法来注入被依赖的实例)
  2. 构造注入(Ioc容器使用构造器来注入被依赖的实例)
设置注入代码如下:

public interface Axe {
   public String shop();
}

public interface Person {
	public void useAxe();

}

public class StoneAxe implements Axe{

	@Override
	public String  shop() {
		// TODO Auto-generated method stub
	return "用石头斧子";
		
	}
	

}
public class Cinese implements Person {
	private String name;
	private Axe axe;


	@Override
	public void useAxe() {
		// TODO Auto-generated method stub
		System.out.println("我是"+name+"用"+axe.shop());
		
	}





	public String getName() {
		return name;
	}





	public void setName(String name) {
		this.name = name;
	}





	public Axe getAxe() {
		return axe;
	}





	public void setAxe(Axe axe) {
		this.axe = axe;
	}
	

}


上述两个接口,只是起规范作用,重点看两个实现类,其中cinese需要Axe实例,但是并不知道他要调用的Axe实例在哪,也不知道Axe实例如何实现,这个Axe实例将由Spring容器注入。需要设值注入的属性一定要覆盖set、get方法。

下面看配置:
<bean id="Cinese" class="com.example.test.Cinese">
<property name="axe" ref="StoneAxe"/> 
<property name="name" value="liu"/>
</bean>
<bean id="StoneAxe" class="com.example.test.StoneAxe"></bean>

注意:配置下标签,如果属性的值是某个实现类的实例,要ref;如果是某个具体值需要的是value。class:指定该类的实现类,此处不可以用接口,必须是实现类,Spring容器会使用xml解析器读取该属性值,并利用反射来创建该实现类的实例。

构造注入,关键代码如下:

public class Cinese implements Person {
	private String name;
	private Axe axe;
	public Cinese(String name, Axe axe) {
		super();
		this.name = name;
		this.axe = axe;
	}

	@Override
	public void useAxe() {
		// TODO Auto-generated method stub
		System.out.println("我是"+name+"用"+axe.shop());
		
	}
}

需要构造注入的属性一定要覆盖该属性的构造方法。

配置代码如下:
<bean id="Cinese" class="com.example.test.Cinese">
<constructor-arg ref="StoneAxe"/>
<constructor-arg value="liu"/>
</bean>
<bean id="StoneAxe" class="com.example.test.StoneAxe"></bean>

Bean配置项

  1. id:在整个ioc容器,唯一标识。
  2. class:具体实例化的类。
  3. scope:作用域。
  4. constructor arguments:构造器参数。
  5. properties:属性。
  6. autowiring mode:自动装配模式。
  7. lazy-initialization mode:懒加载。
  8. initialization/destruction method:初始化,销毁。

Bean作用域

  1. singleton:单例,指一个Bean容器中只存在一份。(默认作用域)
  2. propotype:每次请求(每次使用)创建新的实例,destory方式不生效。
  3. request:每次http请求创建一个实例且仅在当前request内有效。
  4. session:同上,每次http请求创建,当前session有效。
  5. global session:基于portlet的web中有效(portlet定义了global session),如果是在web中,同session。

Bean生命周期

  1. 定义
  2. 初始化
  3. 使用
  4. 销毁
bean初始化两种方法:
  • 提供初始化、销毁方法,在配置文件中配置。
public class BeanLife {

	public void init(){
		System.out.println("spring 开始初始化!!");
	}
	
	public void destory(){
		System.out.println("spring 开始销毁!!!");
	}

}

配置信息:

<bean id="BeanLife" class="com.example.test.BeanLife" init-method="init" destroy-method="destory"></bean>
  • 实现接口。
public class BeanLife implements InitializingBean,DisposableBean {

	@Override
	public void destroy() throws Exception {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		
	}
}

全局默认初始化:

还是在一个bean中提供初始化和销毁的方法。

配置信息 :

<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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
	default-init-method="init" default-destroy-method="destory">

在上述几个初始化,实现接口的方式优先级最高。

Bean的Aware接口

  1. ApplicationContextAware  获取Bean容器上下文
  2. BeanNameAware   获取Bean的id

Bean自动装配

  • No:不做任何操作。(默认转载模式)
  • byName:就是通过Bean的属性名字进行自动装配,在Spring的配置文档XML中,找到一个要装配同样名字的Bean。
该装载模式,主要用于设值注入,在实现类中提供相应的set方法,主要和设值注入不同,就是配置。配置如下:

<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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
    default-autowire="byName"
	>
<bean id="Cinese" class="com.example.test.Cinese">
<property name="name" value="liu"/>
</bean>
<bean id="stoneAxe" class="com.example.test.StoneAxe"></bean>
</beans>

你会发现获取实例的属性,并没有,代替的是修改装载模式。在这里特别要注意的是,根据name去相应的bean,一定注意属性的set方法,比如setAbc,那么寻找bean的id一定是abc,就是除去set的,首字母小写,其他不变,否则会报错。

  • byType:就是如果XML中正好有一个与属性类型一样的Bean,就自动装配这个属性。如果有多这样的Bean,就报错。如果找不到Bean,则什么事都不发生。
<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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
    default-autowire="byType"
	>
<bean id="Cinese" class="com.example.test.Cinese">
<property name="name" value="liu"/>


</bean>
<bean class="com.example.test.StoneAxe"></bean>
<bean id="BeanLife" class="com.example.test.BeanLife"></bean>
</beans>

修改装载模式为根据类型查找bean,Ioc容器会根据属性的类型,去寻找相应class的bean。在此过程中,bean有无id无所谓。
  • Constructor:就是根据构造函数的参数自动装配。
<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
    default-autowire="constructor"
	>
<bean id="Cinese" class="com.example.test.Cinese"></bean>
<bean class="com.example.test.StoneAxe"></bean>
<bean id="BeanLife" class="com.example.test.BeanLife"></bean>
</beans>

public class Cinese implements Person {
	private StoneAxe stoneAxe;
	
	public Cinese(StoneAxe stoneAxe) {
		super();
		this.stoneAxe = stoneAxe;
	}

	@Override
	public void useAxe() {
		// TODO Auto-generated method stubhy
		System.out.println("用"+stoneAxe.shop());
		
	}
}

Ioc容器首先会进行构造器的寻找,然后根据构造器的参数类型,去找相应的Bean,即完成装配。

总结:

在bean配置文件里设置autowire属性进行自动装配将会装配bean的所有属性,然而,若只希望装配个别属性时,autowire就不够灵活了。
autowire属性要么根据类型自动装配,要么根据名称自动装配,不能两者兼而有之
一般情况下,在实际的项目中很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力。

Resourse

是针对资源文件的统一接口,Spring通过它来调用资源文件。
Resourse分类
  1. UrlResource:url对应的资源,根据一个url地址即可构建。
  2. ClassPathResource:获取类路径下的资源文件。
  3. FileSystemResource:获取文件系统里面对的资源。
  4. ServletContextResource:ServletContext封装的资源,用来访问ServletContext环境下的资源。
  5. InputStreamResource:针对于输入流封装的资源。
  6. ByteArrayResource:针对于字节数组封装的资源。
ResourceLoader:资源加载类。


下面是具体的代码:
Resource s = context.getResource("classpath:com/example/test/config1.txt");
		System.out.println(s.getFilename());
		try {
			System.out.println(s.contentLength());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

注意:如果你在项目下添加资源文件,采用的前缀是classpath。如果在默认不加的情况,是按照classpath查找。前缀file是外部文件;http是网络资源。

类的自动检测与注册bean

从spring3.0开始,提供java而不是xml定义bean,通过用注解来提供,比如:@configuration,@bean,@import,@dependson。
@component是一个通用的注解,可用于任何bean,@respository,@service,@contrSoller是更有针对性的注解,这三个注解基于@component 。
@repository通常用注解dao类,即持久层,
@Service通常用于注解Service类,即服务层 ,
@controller通常用于controller类,即控制层(mvc)。

扫描过程中组件被自动检测,那么bean名称是由BeanNameGenerator生成的(@component,@repository,@service,@controller都会有个name属性用来显示设置Bean Name),如果没有name属性,默认的bean name 就是Bean类,将首单词小写作为name,如果要实现自定义bean命名策略,实现BeanNameGenerator接口,并一定要包含一个无参构造函数。

通过注解来实现bean的作用域,其中注解默认作用域的值是prototype,也可以自定义scope策略,实现scopemetadataResolver接口并提供一个无参构造器

使用过滤器进行扫描:



下面具体代码实现:
package com.example.test;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Scope()
@Component
public class TestAnnocation {
       public void test(){
    	   System.out.println("我不是xml注册的bean");
       }
       public void myHashcode(){
    	   System.out.println(this.hashCode());
       }
}

applicationxml配置文件:

<?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
	 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
	 http://www.springframework.org/schema/context
	 http://www.springframework.org/schema/context/spring-context.xsd"
          default-autowire="constructor"
	>
	<context:component-scan base-package="com.example.test"/>
</beans>

注意一定要在命名空间添加,否则下面使用context标签会出错。

@required @autowired 自动装配

@required注解适用bean属性的setter方法,这个注解仅仅表示,受影响的bean属性必须在配置时被填充,通过在bean定义或通过自动转配一个明确属性值。在现在的开发中,用的多的是@Autowired注解可以用于构造器、setter、成员变量。

在默认情况下,如果因找不到合适的bean将会导致自动装载失败抛出异常,可以通过下面的方式避免

	 @Autowired(required =false)
	public Cinese(StoneAxe stoneAxe) {
		super();
		this.stoneAxe = stoneAxe;
	}



每个类只能有一个构造器被标记required=true。

下面具体代码实现:


package com.example.test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Cinese implements Person {
	 @Autowired
	private StoneAxe stoneAxe;
	 @Autowired
	public Cinese(StoneAxe stoneAxe) {
		super();
		this.stoneAxe = stoneAxe;
	}

	
	@Override
	public void useAxe() {
		// TODO Auto-generated method stubhy
		System.out.println("用"+stoneAxe.shop());
		
	}

	public StoneAxe getStoneAxe() {
		return stoneAxe;
	}
	 @Autowired
	public void setStoneAxe(StoneAxe stoneAxe) {
		this.stoneAxe = stoneAxe;
	}
}

上述StoneAxe类,也必须申明为可以扫描的bean,否则找不到,装载自然失败。

可以使用@autowired注解那些众所周知的接口,就可以使用它的实例。比如BeanFactory、ApplicationContext、Environment、ResourceLoader。

可以通过添加注解给需要该类型的数组的字段或方法,以提供ApplicationContext中的所有特定类型的bean,也可以用于装配key为String的Map,如果希望数组有序,可以让bean实现ordered接口或者@order注解。仅限于数组,map不行。

下面是具体代码:
public interface BeanInterface {

}

@Component
@Order(1)
public class BeanInterfaceImplone implements BeanInterface {

}

@Component
@Order(2)
public class BeanInterfaceImpltwo implements BeanInterface {

}

@Component
public class BeanInvoker {
	@Autowired
	private List<BeanInterface> list ;
	
	private Map<String, BeanInterface>  map ;
	public void say(){
	/*	for(int i =0;i<list.size();i++){
			System.out.println(list.get(i).getClass().getName());
		}*/
		for(BeanInterface bean :list){
			System.out.println(bean.getClass().getName());
		}
		
	}
	public void say1() {
		// TODO Auto-generated method stub
       for(Map.Entry<String,BeanInterface> entry: map.entrySet()){
    	   System.out.println(entry.getKey()+"   "+entry.getValue().getClass().getName());
       }
	}

}

@autowired自动装载List泛型对象,如果是接口,就自动装载接口实现类的对象,所以在接口实现类要添加@componment。

@qualifter和@resource

按类型自动装配可能有多个bean实例的情况,可以使用spring的@qualifiter注解缩小范围(或者指定唯一),也可以用于指定单独对的构造器参数或者方法参数。

@autowired通常用于按类型进行自动装配。
@autowired和@qualifter一起使用是按照name进行自动装配。@qualifter的value是引用的bean的name,如果是自动扫描的就是bean类名的第一个字母小写。
@Resource注解,JSR-250标准注解,推荐使用它来代替Spring专有的@Autowired注解。@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按byName自动注入罢了。@Resource有两个属性是比较重要的,分别是name和type,Spring将 @Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。@resourse没有显示name时,如果定义在set方法上,就是set方法的方法名,如果定义在变量上,就是该变量的名称。

@autowired适用于fields,constructors,multi-argument methods这些允许在参数级别使用@qualifiter注解缩小范围的情况。
@resources适用于成员变量,只有一个参数的setter方法,所以在目标是构造器或者一个多参数方法时,最好的方式是使用qualifiter。

	@Autowired
	@Qualifier("beanInterfaceImplone")
	private BeanInterface bean;

@bean

SpringIoc容器管理的新对象的方法,类似xml配置文件呢的<bean>

可以在spring的@configuration注解的类中使用@bean注解任何方法。

例子代码如下:

public interface Store {

}

public class StringStore implements Store {
	private void init() {
		// TODO Auto-generated method stub
    System.out.println("this is init");
	}
	private void destory() {
		// TODO Auto-generated method stub
	    System.out.println("this is destory");

	}

}

@Configuration
public class StoreConfig {
	@Bean(name="stringstore",initMethod="init",destroyMethod="destory")
	public StringStore getStringStore(){
		return new StringStore();
	}

}
需要注意的是:如果@bean不显示指定name,则默认的就是返回实例的方法名。指定初始、销毁方法,是bean在ioc容器加载、销毁执行的。

@ImportResource与@value

我们该如何在spring用注解引进资源属性文件,properties文件中存放的属性是按key、value,例如数据库连接信息。代码如下:

在当前包下添加一个属性文件



在spring文件中引入资源属性文件

<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
	 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
	 http://www.springframework.org/schema/context
	 http://www.springframework.org/schema/context/spring-context.xsd"
    
	>
	<context:component-scan base-package="com.example.test"/>
	<context:property-placeholder location="classpath:com/example/test/config.properties"/>
</beans>

public class MyJdbcInfo {
	private String url;
	private String username;
	private String userpass;
	public MyJdbcInfo(String url, String username, String userpass) {
		super();
		this.url = url;
		this.username = username;
		this.userpass = userpass;
		System.out.println(this.url+this.username+this.userpass);
	}
	
          
}

@Configuration
@ImportResource("classpath:applicationContext.xml")
public class JdbcConfig {
	@Value("${url}")
    private String url;
	@Value("${jdbc.username}")
    private String username;
	@Value("${userpass}")
    private String userpass;
    @Bean(name="jdbc")
    public MyJdbcInfo getMyJdbcInfo(){
    	return new MyJdbcInfo(url, username, userpass);
    }  
    
}

通过@value将属性文件值赋给对应属性值。

@scope

这个注解主要用于bean的作用域和代理模式。

 @Scope(value="prototype",proxyMode=ScopedProxyMode.DEFAULT)

基于注解的泛型自动装配

public interface Store<T> {

}

public class StringStore implements Store<String> {
	private void init() {
		// TODO Auto-generated method stub
    System.out.println("this is init");
	}
	private void destory() {
		// TODO Auto-generated method stub
	    System.out.println("this is destory");

	}

}

public class IntegerStore implements Store<Integer>{
	

}

@Configuration
public class StoreConfig {
	/*@Bean(name="stringstore",initMethod="init",destroyMethod="destory")
	public StringStore getStringStore(){
		return new StringStore();
	}*/
	@Resource(name="string")
	private Store<String> ss;
	@Resource(name="integer")
	private Store<Integer>is;
	@Bean(name="string")
	public StringStore getStringStore(){
		return new StringStore();
	}
	@Bean(name="integer")
	public IntegerStore getiIntegerStore(){
		return new IntegerStore();
	}
	@Bean(name="teststore")
	public StringStore testStore(){
		System.out.println(ss.getClass().getName()+"        "+is.getClass().getName());
		return new StringStore();
	}
	

}

需要注意这里泛型自动装配的时候为啥不用@autowired,原因下面的bean有两个返回类型一致,会导致自动装配失败。

jsr中@resourse以及初始化回调和销毁回调

@Repository
public class JslDao {
	public void save(){
		System.out.println("this is  a method");
	}

}

@Service
public class JslService {
@Resource
   private JslDao dao;
   
   public void save(){
	   dao.save();
   }
   @PostConstruct
   public void init(){
	   System.out.println("init");
   }
   @PreDestroy
   public void destory(){
	   System.out.println("destory");
   }
}

使用jsr330标准注解

@inject等效于@autowired,可以使用于类、属性、方法、构造器。
如果想使用特定名称进行依赖注入,使用@name。
@name与@componment在类注解上是等效的,可以定义一个bean。

@Named
public class JslService {
@Inject
   private JslDao dao;
   
   public void save(){
	   dao.save();
   }
   @PostConstruct
   public void init(){
	   System.out.println("init");
   }
   @PreDestroy
   public void destory(){
	   System.out.println("destory");
   }
}


@Named
public class JslService {
@Inject
   private JslDao dao;
   
   public void save(){
	   dao.save();
   }
   @PostConstruct
   public void init(){
	   System.out.println("init");
   }
   @PreDestroy
   public void destory(){
	   System.out.println("destory");
   }
}
















































































































































































































































































































































































































































































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值