注入方式
- 通过IOC容器创建对象,并为属性赋值★
//日期类型的注入
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd"></constructor-arg>
</bean>
<bean id="date" factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2015-12-31"></constructor-arg>
</bean>
<bean id="person01" class="com.kuang.Person">
<property name="name" value="狂神"></property>
<property name="age" value="25"></property>
<property name="id" value="123"></property>
</bean>
- 根据bean的类型从IOC容器中获取bean的实例★
ApplicationContext ioc = new ClassPathXmlApplicationContext("application.xml");
// Person person = (Person) ioc.getBean("person01");
// Person person = ioc.getBean("person01",Person.class);
- 通过构造器为bean的属性赋值(index,type属性介绍)
<bean id="person03" class="com.kuang.Person">
<constructor-arg name="name" value="小明"></constructor-arg>
<constructor-arg name="age" value="25"></constructor-arg>
<constructor-arg name="id" value="123"></constructor-arg>
<constructor-arg name="bir" ref="date"></constructor-arg>
</bean>
- ·通过p名称空间为bean赋值
导入标签
xmlns:p="http://www.springframework.org/schema/p"
注入属性
<bean id="person04" class="com.kuang.Person" p:age="28" p:id="456" p:name="haha">
</bean>
5.级联属性的注入
<property name="car" ref="car01"/>
<property name="car.price" value="900000"/>
6.通过继承实现bean的配置信息重用
<bean id="person05" class="com.kuang.Person" parent="person04">
<property name="bir" ref="date"></property>
</bean>
7.通过工厂注入(静态工厂、实例工厂)
<!--静态工厂-->
<bean id="factoryPerson" class="com.kuang.PersonFactory" factory-method="getPerson">
</bean>
<!--实例工厂-->
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd"></constructor-arg>
</bean>
<bean id="date" factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2015-12-31"></constructor-arg>
</bean>
8.创建带有生命周期方法的bean
实现BeanPostProcessor接口
public class MyBeanPostProcessor implements BeanPostProcessor {
@Nullable
/*
初始化之前调用的方法
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("[" + beanName +"]bean方法将要调用初始化方法了" );`在这里插入代码片`
return bean;
}
/*
初始化之后调用的方法
*/
@Nullable
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("[" + beanName +"]bean方法将要调用处理方法了");
return bean;
}
}
//注册对象
<bean id="beanPostProcessor" class="com.kuang.MyBeanPostProcessor"></bean>
9.通过注解加bean加入IOC容器中
@Service
@Controller
@Repository
@Component
使用注解加入到容器中的组件,组件的id,默认为组件的类名首字母小写,单例
可以通过组件如@Service(“bookDao”) @Scope(value=“prototype”)
<context:component-scan base-package="com.kuang"/>
排除扫描
<context:component-scan base-package="com.kuang">
<!--扫描的时候可以排除一些不要的组件
type="assignable",指定排除某个具体的类,按照类排除
type="annotation" 指定要排除的规则,按照注解进行排除,标注了指定注解的组件不要
type="aspectj"
type="regex"
expression="": 注解的全类名
-->
<context:exclude-filter type="regex" expression="org.springframework.stereotype.Controller"></context:exclude-filter>
</context:component-scan>
指定只扫描
<context:component-scan base-package="com.kuang" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"></context:include-filter>
</context:component-scan>
@Autowired原理(requireds属性可以更改)
1、先按照类型去容器中找到对应的组件:找到一个就赋值,没找到就抛异常,找到多个则按照变量名作为id继续装配,匹配则装配,若没有匹配则可以用@Qualifier(“bookService”)指定id。也可以加在方法上
依赖泛型注入
public abstract class BaseDao<T> {
public abstract void save();
}
@Repository
public class BookDao extends BaseDao<Book> {
@Override
public void save() {
System.out.println("保存图书");
}
}
@Repository
public class UserDao extends BaseDao<Person> {
@Override
public void save() {
System.out.println("保存用户");
}
}
public class BaseService<T> {
@Autowired
BaseDao<T> baseDao;
public void save() {
baseDao.save();
}
}
@Service
public class BookService extends BaseService<Book>{
}
@Service
public class UserService extends BaseService<Person>{
}
@Resource:扩展性更强,因为是java标准
- 如何为对象list中注入属性
spring的单元测试
@ContextConfiguration(locations = "classpath:application.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class TestDemo {
@Autowired
@Qualifier("person01")
Person person;
public class Book {
private List<String> books;
private Map<String,Object> maps;
private Properties properties;
}
<list>
<!-- <value>张三</value String类型>
<value>李四</value>-->
<ref bean="person01"></ref>
<bean class="com.kuang.Person" p:age="28" p:id="456" p:name="haha"/>
</list>
- 如何为map中注入属性
<property name="maps">
<map>
<entry key="key01" value="张三"></entry>
<entry key="key02" value-ref="person01"></entry>
<entry key="key03">
<bean class="com.kuang.Person" p:age="28" p:id="456" p:name="haha"/>
</entry>
</map>
</property>
3.为Properties注入属性
<property name="properties">
<!--properties中所有的k=v都是String类型的-->
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
提取公共的list map
<util:map id="myMap">
<entry key="key01" value="张三"></entry>
<entry key="key02" value-ref="person01"></entry>
</util:map>
注意:
xml中基本类型的会自动转化
对象的创建按照配置的循序创建bean(可以通过dependence进行更改)
按照类型获取组件,可以获取到这个类型下所有的实现类子类(有多个就报错)
引用外部文件
<context:property-placeholder location="classpath:dbconfig.properties"/>
自动装配
autowire=“byName” 以属性名作为id去容器中找到这个组件,给他赋值
autowire="byType"以属性的类型作为查找依据去容器中找到这个组件
autowire="constructor"按照构造器进行赋值;1.想按照有参类型进行装配,没有就直接为组件赋值为null 2.如果按照类型找到多个,参数的名作为id继续装配;找到就装配,找不到就null
SPEL注入格式#{}调用
<property name="id" value="#{T(java.util.UUID).randomUUID().toString()}"></property>
xml属性注入需要提供get/setter方法 自动@Autowired不需要提供
复杂类型的注入要在标签外进行
<constructor-arg name="bir"><null/></constructor-arg>
ref为严格的引用外部bean 内部bean的
bean的作用域
prototype:多实例
获取的时候才开始创建
singleton:默认为单实例
在容器启动完成之前已经创建好对象,保存在容器中了
任何获取都是获取之前创建好的那个对象
request:web环境下
session
内部bean
<property name="bir">
<bean factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2015-12-31"></constructor-arg>
</bean>
</property>
//外部bean
<constructor-arg name="bir" ref="date"></constructor-arg>
对象对应bean标签
配置注意事项
1)、src,源码包开始的路径,称为类路径的开始即/bin
源码包里面的东西都会合并到类路径里面
web:/WEB-INF/classes/
new ClassPathXMLApplicationContext(“ioc.xml”);IOC配置文件在类路径下;
new FileSystemXmlApplicationContext("F:/ioc.xml); IOC容器的配置文件在磁盘路径下;
Date类型注入
测试Bean:
public class DateBean {
private Date birthday;
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
方式1:利用SimpleDateFormat的构造方法注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" 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="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
<bean id="datebean" class="com.springDemo1.Date类型注入.DateBean">
<property name="birthday">
<bean factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2015-12-31" />
</bean>
</property>
</bean>
</beans>
方式2:纯配置,先自定义CustomDateEditor,再转换类型
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" 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="dateEditor"
class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg>
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd"></constructor-arg>
</bean>
</constructor-arg>
<constructor-arg value="true" />
</bean>
<!-- 使 Spring转换为java.util.Date -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<ref bean="dateEditor" />
</entry>
</map>
</property>
</bean>
</beans>
方式3:先用一个类重写PropertyEditorSupport的setAsText方法,再在配置文件中,配置转换类型就可以了,跟上面方法类似
public class MyDatePropertyEditor extends PropertyEditorSupport {
private String format;
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
// text为需要转换的值,当为bean注入的类型与编辑器转换的类型匹配时就会交给setAsText方法处理
public void setAsText(String text) throws IllegalArgumentException {
SimpleDateFormat sdf = new SimpleDateFormat(format);
try {
this.setValue(sdf.parse(text));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" 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">
<!--方式3:创建一个类 重写PropertyEditorSupport的setAsText方法 -->
<!-- 自定义日期编辑器 -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors"> <!--需要编辑的属性类型,是一个map -->
<map>
<entry key="java.util.Date">
<bean class="com.springDemo1.Date类型注入.MyDatePropertyEditor">
<property name="format" value="yyyy-MM-dd" /> <!--注入需要转换的格式 -->
</bean>
</entry>
</map>
</property>
</bean>
</beans>
测试:
public class DateTest {
@Test
public void testName() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
DateBean bean = (DateBean) context.getBean("datebean");
System.out.println(bean.getBirthday());
}
}
支持当前事务
- PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- PAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)。
不支持当前事务的情况: - PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
- PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
- PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于
spring对象作用域
Spring 3中为Bean定义了5中作用域,分别为singleton(单例)、prototype(原型)、request、session和global session,5种作用域说明如下:
springAOP
JDK动态代理
利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,
在调用具体方法前调用InvokeHandler来处理。
CGLiB动态代理
利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
JDK和CGLib的性能对比
使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在JDK1.6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
在JDK1.6、JDK1.7、JDK1.8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLib代理效率,只有当进行大量调用的时候,JDK1.6和JDK1.7比CGLib代理效率低一点,但是到JDK1.8的时候,JDK代理效率高于CGLib代理