捡框架的小男孩--Spring(二)
补充:scope 的prototype 容器初始化时不创建bean实例,而是每次请求时都会创建实例。bean使用外部属性文件spring2.5之后使用 使用 context:property-placeholder location=""SpEL
补充:scope 的prototype 容器初始化时不创建bean实例,而是每次请求时都会创建实例。
bean使用外部属性文件
spring2.5之后使用 使用 context:property-placeholder location=""
当然要使用这个就得加上命名空间,不然程序可不知道这是什么标签。
xmlns:context="http://www.springframework.org/schema/context"
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<!-- 这里指明 外部属性文件的路径 可以是下面的情况也可以是 相对路径 URL-->
<!-- 例子:location="/test.properties" 应为当前文件和 test.properties都在src-->
<context:property-placeholder location="classpath:test.properties"/>
<bean id="property" class="SQLConnet.PropertyDemo">
<property name="name" value="${name}"></property>
<property name="password" value="${password}"></property>
</bean>
</beans>
这里 ${name}就是获取的外部 (test.properties文件的 name)
name=v5_BAT
password=123456
这么做有什么优点呢:当你的配置文件特别大的时候,再去修改配置文件找到对应的代码就比较耗时了。那么去修改一个外部的文件就显得轻松很多了。
SpEL
-字面值
整数<property name="spel" value="#{5}">
浮点<property name="spel" value="#{5.5}">
科学记数法<property name="spel" value="#{5}">
字符串(使用单引号 或者双引号)
<property name="spel" value="#{"hello spring"}">
<property name="spel" value="#{'hello spring'}">
boolean
<property name="spel" value="#{false}">
-引用bean 相当于ref
<property name="spel" value="#{otherbeanid}">
引用其他bean的属性
<property name="spel" value="#{otherbeanid.name}">
引用其他bean的方法的返回值
<property name="spel" value="#{otherbeanid.hello()}">
等等 简单点说SpEL#{} 花括号内就相当于一个方法体 方法体中可以写的东西基本上都可以 什么 +-*/ 调用方法 if else 三目运算符 。。。。
这里要注意一下调用静态方法 :
T(全类名).静态方法或者属性
IOC容器管理bean的生命周期
-在bean中还有两个属性:init-method 和 destroy-method 来指定在bean创建事初始化和销毁时执行的代码。
新建测试类 这里多了两个方法 :init() destory() (名字自拟)
package Test;
public class LifeDemo {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
System.out.println("this is setway");
}
public LifeDemo() {
// TODO Auto-generated constructor stub
System.out.println("this is constructor");
}
private void init() {
// TODO Auto-generated method stub
System.out.println("this is initway");
}
private void destory() {
// TODO Auto-generated method stub
System.out.println("this is destoryway");
}
}
bean 的写法就是多了 两个属性 属性值分别是 我在该类中创建的
<bean id="lifeDemo" class="Test.LifeDemo"
init-method="init"
destroy-method="destory"
>
<property name="age" value="20"></property>
</bean>
测试类
package Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext ioc=new ClassPathXmlApplicationContext("lifeContext.xml");
LifeDemo ld=(LifeDemo) ioc.getBean("lifeDemo");
ioc.close();
}
}
结果:
this is constructor
this is setway
this is initway
this is destoryway
先分析一下结果: 在在set方法执行之后执行 init-method所指定的方法(类初始化的时候执行)。在调用close方法之后执行。
ClassPathXmlApplicationContext ioc=new ClassPathXmlApplicationContext("lifeContext.xml");
细心的人会发现前面都用的是 ApplicationContext 现在怎么换了。下面给大家梳理一下类的层次结构
BeanFoctory (I)
|-ApplicationContext (I)
|-ClassPathXmlApplicationContext (C)
|-FileSystemXmlApplicationContext (C)
这里为什么不用接口不用说肯定是用到实现类的特有方法。
-bean的后置处理器
后置处理器需要一个类来实现beanPostProcessor 可见是源码是用 钩子模式实现的。
不多说先创建一个类实现一下。
住:后置处理器是处理所有bean 的
package Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
*实现接口的两方法
*第一个参数是当前使用后置处理器的bean实例
*第二个参数是当前bean id
*
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanname)
throws BeansException {
System.out.println("this is aferinitway" +bean+" "+beanname);
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanname)
throws BeansException {
System.out.println("this is beforeinitway" +bean+" "+beanname);
return bean;
}
}
<bean id="lifeDemo" class="Test.LifeDemo"
init-method="init"
destroy-method="destory"
>
<property name="age" value="20"></property>
</bean>
<!--增加下面的配置-->
<bean class="Test.MyBeanPostProcessor"></bean>
结果
this is constructor
this is setway
this is beforeinitwayTest.LifeDemo@6e06451e lifeDemo
this is initway
this is aferinitwayTest.LifeDemo@6e06451e lifeDemo
this is destoryway
结果显而易见什么时候调用都清楚。
发现处理器处理以后返回的是bean实例。那么也就可以对bean实例进行更改。如果不返回会怎么样呢(会抛出异常)后面就没有这个bean实例。
通过工厂配置bean
用到的任然是bean的属性 factory-method .来指定嗲用工厂的方法产生实例。
当然你要使用工厂就能有个可用的工厂实例 或者 静态的方法
如果需要创建工厂实例 用bean 创建 然后在使用的地方加上 factory-bean="factorybeanid"
其他不变。
如果是一个静态工厂就更简单了直接使用如下
<bean id="lifeDemo1"
class="Factory.StaticFactory"
factory-method="getLifeDemoInstance"
>
<!--方法的参数放在这里-->
<constructor-arg value="first"></constructor-arg>
</bean>
通过FatoryBean 配置bean
首先要有一个类实现FactoryBean
package Factory;
import org.springframework.beans.factory.FactoryBean;
import Test.LifeDemo;
public class MyFactoryBean implements FactoryBean<LifeDemo> {
private int age;
public void setAge(int age){
this.age=age;
}
@Override
public LifeDemo getObject() throws Exception {
// TODO Auto-generated method stub
return new LifeDemo(age);
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return LifeDemo.class;
}
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return true;
}
}
配置直接使用我们实现的类
<bean id="life" class="Factory.MyFactoryBean">
<property name="age" value="20"></property>
</bean>
底层会自动调用 getObject() 并吧获得的实例作为bean实例
通过注解来配置bean
住:这里如果没导入aop的包 会报 classnotfound org/springframework/aop/TargetSource 的错误。导入一下jar包就行了。
前面用的都是xml来配置现在讲一种更简单的方法通过注解
bean注解 声明
@Component 标示 是Spring管理的组件
@Repositroy 在数据访问层、持久化层 dao
@Service 业务逻辑层
@Controller 表现层
在类上声明这个类就是spring 管理的类了。
当然不是用注解就没有xml的事了。我们仍然要在spring的配置文件中 加上点东西
<context:component-scan base-package="这里填上父包"></context:component-scan>
这样就会扫描父包及其以下的所有被spring管理的包(有声明的、有注解的)
在c测试类中我们又该怎么拿到这个bean的实例呢
1.spring 默认的命名规则为被注解的类 首字母小写(UserController->userController)
2.可以自己命名(@Repositroy(controller))
命名以后就相当于id 可以通过getBean(id)来获取实例
如果不想都扫描我们就可以对其中做一些限定
<context:component-scan base-package="这里填上父包"
resource-pattern="/*.class"
//指定扫描的资源
></context:component-scan>
还有可以根据 annotation 来指定
同理
<context:component-scan base-package="这里填上父包">
<ontext:exclude-filter type="annotation"
expression="....Repository"
</context:component-scan>
有exclude就有include 意思是只有这个可以
当然要使用include 要 包默认的过滤器改为false
<context:component-scan base-package="这里填上父包"
use-default-filter="false"
>
<ontext:exclude-filter type="annotation"
expression="....Repository"
</context:component-scan>
type 中还assingable 这个是对类进行限制同理很容易使用
对bean进行注入少不了bean之间的组合;
package BeanByAnnotation.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import BeanByAnnotation.respository.UserRes;
@Service
public class MyServcieImpel implements myservice {
/**
这里只要在组合的地方加上@Autowired注解即可 (有没有set方法都一样 底层只是找到要注解什么bean 不会去执行set方法来注入)。找到要注入对象spring会去容器中查找是否有对应兼容的bean (为什么说是兼容 有的bean是实现一些接口)找到就注入。
如果没找到会抛出异常。如果不想抛出异常可以@Autowired(require=false)这样如果没找到这个实例就是null
那又如果有很多bean都是兼容的就要根据命名来判断是哪一个了。如果只声明没有指明具体的名字就会默认为首字母小写前面提到过 。
解决方法@Qualifier("指定名字") 可以写在属性 方法上 甚至 set方法传入的参数上
*/
@Autowired
private UserRes userRes;
public void setUserRes(UserRes userRes){
this.userRes=userRes;
}
@Override
public void print() {
// TODO Auto-generated method stub
System.out.println("servcie print");
userRes.save();
}
}
spring4.x的新特性
泛型依赖注入
更多推荐
所有评论(0)