springIOC笔记
环境搭建
导入
commons-logging-1.2
log4j-1.2.16
spring-beans-4.2.4.RELEASE
spring-context-4.2.4.RELEASE
spring-core-4.2.4.RELEASE
spring-expression-4.2.4.RELEASE六个jar包
对应的XML配置文件
<?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">
</beans>
备注:此段xml在spring的html/xsd-configuration.html路径下的html中scheam约束中有
bean创建的两种规则
一.BeanFactory :提供一种延时加载思想来创建bean对象,bean对象什么时候用什么时候创建
获取容器
Resource resource = new ClassPathResouce("bean.xml");//创建一个resouce对象。参数为配置文件(xml文件)
BeanFactory factory = new XmlBeanFactory(resouce);//获取容器,参数为上一步获取的resouce根据id获取对象
ICustomerService customerService = (ICustomerService)factory.getBean("ICustomerService");ApplicationContext :提供一种立即加载思想来创建bean对象,只要一解析完配置文件,就立即创建bean对象
获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml" );根据id获取对象
ICustomerService is = (ICustomerService) ac.getBean("ICustomerService");
bean的三种创建方式(修改xml中的配置文件)
调用默认无参构造函数创建(如果没有无参构造函数,则创建失败) 实际开发中此种方式用的最多
//XML配置资源,把对象交给spring来创建
<bean id="ICustomerService" class="com.baidu.service.ICustomServiceImpl"></bean>
//测试类中通过xml获取对象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml" );
ICustomerService is = (ICustomerService) ac.getBean("ICustomerService");使用静态工厂中的方法创建
//配置使用静态工厂创建bean对象
<bean id="staticCustomerService" class="com.baidu.factory.CustomerFactory" factory-method="getCustomerService"></bean>
//id后为类名。class后为工厂的全限定类名,factory-method后为工厂类获取类对象的方法
//测试类中通过xml获取对象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml" );
ICustomerService is = (ICustomerService) ac.getBeanid("staticCustomerService") ;
使用实例工厂方法创建
//配置使用实例工厂创建bean对象
<bean id="instanceFactory" class="com.baidu,factory.InstanceFactory" ></bean>
//先创建工厂对象实例
//id后为工厂类(名字可以随便起的,但要有意义),class后为工厂的全限定类名
<bean id="instanceFactory" factory-bean="InstanceFactory"
factory-method="getICustomerService" ></bean>//创建此实例用factory-bean对象里面的getICustomerService方法
//id为实例类名,factory后为工厂类名,factory-method后为工厂类的方法 :根据此工厂类的方法创建实例类
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml" );
ICustomerService is = (ICustomerService) ac.getBeanid="staticCustomerService" ;bean的作用范围
<bean id="ICustomerService" scope="prototype" class="com.baidu.service.ICustomServiceImpl"></bean>它可以通过bean的配置文件来调整作用范围
singleton :单例的(默认值)
prototype :多例的(当我们让spring接管struts2的action创建时,action必须创建此值)
request :一次请求和当前请求的转发
session :一次会话
globalsession :作用范围是一次全局会话
bean的生命周期
涉及bean标签的两个属性:
init-method
destory-method
<bean id="ICustomerService" scope="prototype" init-method="init" destroy-method="destory" class="com.baidu.service.ICustomServiceImpl"></bean>单例:
出生:容器创建的时候对象出生
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml" );
活着:容器在对象就一直存在
ICustomerService is = (ICustomerService) ac.getBeanid="staticCustomerService" 死亡:容器被销毁了对象就被销毁了
ac.close();
//销毁容器 由于ApplicationContext对象没有close方法,所以不能使用多态
多例:
出生:每次使用的时候创建对象
ICustomerService is = (ICustomerService) ac.getBeanid="staticCustomerService" ;
活着:只要对象在使用中就一直活着
死亡:当对象长时间不使用,并且没有别的对象引用时,由java的垃圾回收器回收
spring的依赖注入三种方式
使用构造函数注入
涉及的标签:constructor-arg
标签的属性:
type:指定参数的类型
index:指定参数的索引位置,从0开始
name:指定参数的名称 (常用)
==========上面三个属性是指定给哪个参数赋值,下面两个属性指定赋什么值
value:指定基本数据类型或String类型
ref:指定其他bean类型的数据
标签出现的位置:写在bean标签的内部
<bean id="customerService" class="com.baidu.service.CustomerServiceImpl">
<constructor-arg name="driver" value="com.baidu.jdbc.Driver"></constructor-arg>
第一个参数为成员变量,第二个为变量的值,需要类提供一个有参的构造函数
<constructor-arg name="today" ref="now"></constructor-arg></bean>
<bean id="now" class="java.util.Date"></bean>//其他bean类型使用set方法注入
涉及的标签:property
标签的属性:
name:指定set方法的名称
==========上面属性是指定给哪个参数赋值,下面两个属性指定赋什么值
value:指定基本数据类型或String类型
ref:指定其他bean类型的数据
标签出现的位置:写在bean标签的内部
<bean id="customerService" class="com.baidu.service.CustomerServiceImpl">
<property name="driver" value="com.mysql.jdbc.Driver"> </property>
第一个参数为方法的名称(set后面的,首字母改小写),第二个参数为设置的值
</bean>基本类型和String类型
其他bean类型(必须在spring的配置文件中出现过的bean)
复杂类型(集合类型) !!!结构相同,标签可以互换
使用注解注入(注入的数据类型有3类:)
<bean id="customerService" class="com.baidu.service.customerService">
<property name="myArray">
<array> //或者是List <list>
<value>AAA</value>
< value>CCC</value>
<value>BBB</value>
` </array>
</property>
<property name="myList">
<list>
<value>AAA</value>
<value>CCC</value>
<value>BBB</value>
` </list>
</property>
<property name="myMap">
<map>
<entry key="TA" value="AAA"></entry>
<entry key="TB>
<value>BBB</value>
</entry>
` </map>
</property>
<property name="myMap">
<prop key="TA">AAA</prop>
` </property>
</property>
</bean>
Spring基于注解的IOC配置(导入aop.jar包) 没有复杂类型的注解(集合类型)
需要导入另一个shcema约束
<?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.xsd"> <!-- bean definitions here -->
</beans>
用于创建bean对象的注解
@Component
作用:相当于配置了一个bean标签
//<bean id="" class=""></bean>
出现位置:接口,类,enum,。。上面
属性:value 含义是指定bean的id,当不写时,它有默认值,默认值时是:当前类的短名首字母小写
由此注解衍生的三个注解:
@Controller 一般用于表现层注解
@Service 一般用于业务层
@Repositort 一般用于持久层 @Repositort("customerDaoImpl")
设置bean的id
它们和@Component的作用及属性都是一样的导入之后需要告知spring 再创建容器时要扫描的包,当配置了此标签之后,spring创建容器就会区指定的包及其子包下找对应的注解
标签是再一个context的名称空间里,所以必须先导入context名称空间
<context:component-scan base-package="com.baidu"><context:component-scan >
在xml中告知spring需要扫描的包
## 用于注入数据的注解
@Autowired
作用:自动按照类型注入,只要有唯一的类型匹配就能注入成功。
如果注入的bean在容器中类型不唯一时,它会把变量名称作为bean的id,在容器中查找,找到后也能注入成功
如果没有找到一致的bean的id,则报错
当我们使用注解注入时,set方法就不是必须的了
@Qualifier
注入类成员时需要将@Autowired写在其上面
作用: 在自动按照类型注入的基础之上,再按照bean的id注入.它再给类成员注入数据时,不能独立使用,但是再给方法的形参注入数据时,可以独立使用 属性: value : 用于指定bean的id
@Resource 作用:直接按照bean的id注入。
属性:name 用于指定bean的id name不能省略,value可以省略
以上三个注解都用于注入其他bean类型,
@Value 它可以借助spring的el表达式读取properties文件中的配置
作用:用于注入基本类型和String类型数据
属性: value 用于指定要注入的数据
用于改变作用范围的注解
@Scope 作用:改变bean的作用范围
属性 value : 用于指定bean的作用范围取值与xml中的scope属性取值是一样的。singleton(单例)
prototype(多例)
request session globalsession
和生命周期相关的注解
@PostConstruct 作用:用于指定初始化方法 相当于init-method @PreDestory 作用:用于指定销毁方法 相当于destory
spring的新注解
@configuration 此注解表示将此类看作spring的配置类
创建一个spring类,作用相当于bean.xml@ComponentScan({"com.baidu"})
//此注解作用表示spring在创建容器前读取此包下Annotation,里面的参数为注解存在的包,可以传一个String数组
public class SpringConfiguration{@bean(name="runner")
//它是把方法的返回值存入spring容器中。该注解有一个属性name 用于指定bean的id,当不指定时有默认值,为方法名称
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
}
@Bean(name="runner")
//它是把方法的返回值存入spring容器中。该注解有一个属性,name:用于指定bean的id。当不指定时它有默认值,默认值是方法的名称。
@bean
public DataSource createDataSource(){
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.set("jdbc相关的配置信息")
return ds;
}
//后面创建容器需要用到bean.xml用另一个类代替ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
//里面传配置信息的字节码文件
@import(Class<T>[] c )
//里面传一个类的class文件,表示加载此类
@Value("${jdbc.url}")
//表示读取配置文件里面的key为此字符串的value并且赋值给变量
private String url;
@Configuration//它就是把当前类看成是spring的配置类
@ComponentScan({"com.baidu"})@Import({JdbcConfig.class})//导入其他配置类@PropertySource("classpath:config/jdbcConfig.properties")
// 表示加载此配置文件的内容
public class SpringConfiguration {}
@Bean
//在spring4.3.2之前没有解析器,所以需要自己创建,4.3.5后自带,不用自己创建
public static PropertySourcesPlaceholderConfigurer createPropertySourcesPlaceholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();
}
(@Qualifier("ds1")DataSource dataSource
//方法的参数上面
//当bean返回多个同类型的数据源时,哪个bean的id与数据源变量名一致就用哪一个,如果没有一致的,可以用@Qualifier注入dataSource的id
spring整合junit
//第一步:拷贝spring-test-4.2.4.RELEASE.jar
//第二步:使用junit提供的一个注解,把原有的main函数替换掉,换成spring提供的
@RunWith(SpringJUnit4ClassRunner.class) 这个注解可以替换junit原有的main函数
//第三步:使用spring提供的注解告知spring,配置文件或注解类所在的位置
@ContextConfiguration(classes={SpringConfiguration.class}) 如果时纯注解使用class 是xml使用location={"classpath:bean.xml"}
//要换的类:SpringJunit4ClassRunner
================================
动态代理
作用:在不改变源码的基础上,对已有方法进行增强(它是AOP思想的实现技术) 分类:基于接口的动态代理:
要求:被代理类最少实现一个接口
涉及的类:Proxy
创建代理对象的方法:
new ProxyInstance(ClassLoader,Class[],InvocationHandler)
参数的含义:
ClassLoader:类加载器,和被代理对象使用相同的方法,一般都是固定写法 People.getClass().getClassLoader()
Class[] : 字节码数组,和被代理对象实现相同的接口(要求代理对象和被代理对象实现相同的接口),一般都是固定写法 People.getClass().getInterface() InvocationHandler: 它是一个接口,就是用于我们提供增强代码的,我们一般都是写一个该接口的实现类,该实现类也可以是匿名内部类
它的含义就是如何代理,谁用谁写(执行被代理对象的任何方法都会经过该方法),需要实现invoke方法
invoke(Object proxy,Method method,Object[] args)
Object proxy: 代理对象的引用,不一定每次都用
Method method:当前执行的方法
Object[] args:当前执行方法所需要的参数
返回值:当前执行方法的返回值
基于子类的动态代理
要求:被代理对象不能是最终类,不能被final修饰
提供者:第三CGLib,需要导入两个jar包(asm.jar,cglib.jar)
涉及的类:Enhancer
创建代理对象的方法:create(Class,Callback);
参数的含义:
Class:被代理对象的字节码
Callback:如何代理.它和InvocationHandler的作用一样,它也是一个接口,我们一般使用该接口的子类接口MethodInterceptor
在使用时我们也是创建该接口的匿名内部类
执行被代理对象的任何方法都会经过该方法,它和基于接口动态代理的invoke方法的作用是一模一样的
Enhancer.create(other.getClass,new MethodIntercepto(){
} )
方法的参数:
前面三个和invoke方法的参数含义和作用都是一样的
MethodProxy methodProxy:当前执行方法的代理对象,一般不用
new MethodInterceptor(){
public Object intercept(Object proxy,Method method,Object[] args,MethodProxy args2) throws Throwable{
}
}
spring的aop
//导入aop的名称空间,并且使用aop:config开始aop的配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
把通知类交给spring来管理
<bean id="logger" class="com.baidu.utils.Logger"><bean>
配置service 基于xml的aop配置步骤:想要使用spring的aop,必须导入aop的jar包
<bean id="customerService" class="com.baidu.service.impl.CustomerServiceImpl"></bean>
//使用aop:config开始aop的配置
<aop:config>
使用aop:aspect配置切面,id属性用于给1切面提供一个唯一标识 ref:属性,用于应用通知Bean的id
<aop:aspect id="logAdvice" ref="Logger">
** 配置通知的类型,指定增强方法何时执行,method属性:用于指定增强方法的名称,pointcut属性:用于指定切入点表达式
全匹配方式:
切入点表达式:关键字:execution(表达式) 表达式写法: 访问修饰符 返回值 包名.. 类名 方法名(参数列表)
访问修饰符可以省略
返回值可以用通配符,表示任意返回值 通配符是*
包名可以使用通配符,表任意包,但是有几个包就需要写几个* *.*.*.*
包名可以使用.. 表当前包及其子包 com.. *..
类名和方法名都可以使用通配符: *.*()
参数列表可以使用具体类型,来表示参数类型
基本类型直接写类型名称:int
引用类型必须是包名.类名 java.lang.Integer
参数列表可以使用通配符 * 表示任意参数类型,但是必须要有参数
也可以使用 .. 表示有无参数均可,有参数可以是任意类型
全通配方式: * *..*.*(..)
**/
<aop:before method="printLog"
pointcut="execution(public void com.baidu.service.impl.CustomerServiceImpl.savaCustomer )">
</aop:before>
</aop:config>
springAOP的XML和注解
1.导入jar包aopalliance-1.0.jar aspectjweaver-1.8.7.jar spring-aop-4.2.4.RELEASE.jar spring-aspects-4.2.4.RELEASE.jar
第一步:
创建通知类,将通知类交给spring来管理 <bean id="logger" class="com.baidu.logger">
第二步:
导入aop的命名空间,并且使用aop:config开始aop的配置
<aop:config>
第三步:使用aop:aspect配置切面,id属性用于给切面提供一个唯一标志,ref属性:用于应用通知bean的id
<aop:aspect id="logAdvice" ref = "logger">
第四步:配置通知类型(前置,后置,异常,最终,环绕),指定增强方法何时执行,method属性:用于指定增强方法的名称
,pointcut属性:用于指定切入点表达式(对哪些方法进行增强) 写法:访问修饰符 返回值 包名.. 类名 方法名(参数列表)>
<aop:before method="printLog" pointcut="execution(* *..*.*(..)" / > 前置通知
<aop:after-returning method="afterReturningPrint" pointcut-ref="切入点表达式"> 后置通知
<aop:after-throwing method="通知的方法" pointcut-ref=""> 异常通知
<aop:after metho="" pointcut-ref=""> 最终通知
<aop:around method="logger类中的方法(环绕通知的方法)" pointcut="pt1">
</aop:aspect>
</aop:config>
定义通用的切入点表达式,如果是写在了aop:aspect标签内部,则表达式只有当前切面可用
<aop:pointcut expression="execution(* *..*.*(..))" id="pt1"> 写在<aop:config> 标签下表都可用
环绕通知:当配置了环绕通知之后,切入点方法没有执行,而环绕通知里面的方法执行了,由动态代理可知,环绕通知指的是invoke方法,并且里面由明确的方法调用,而我们环绕通知中没有明确切入点方法调用.
解决:
spring为我们提供了一个接口:ProceedingJointPoint,该接口可以作为环绕通知的方法参数来使用
在程序运行时,spring框架会为我们提供该接口的实现类,让我们使用
该接口中有一个方法: proceed() , 它的作用就等同于method.invoke方法,就是明确调用业务层的核心方法
public Object aroundPrintLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try{
//前置通知
rtValue = pjp.proceed()
//后置通知;
}catch(Throwable t){
异常通知 method
}finally{
sout //最终通知
}
return rtValue;
}
注解aop
需要导入context名称空间
<context:component-scan base-package="com.baidu" /> //配置扫描的包
<aop:aspectj-autoproxy /> //需要开启spring对aop注解的支持
@Component("logger")
@Aspect //写在通知类上,就表示配置了切面
//在类里面的方法配置通知类型 @Before("pt1()") @AfterReturning("pt1()") @AfterThrowing("pt1()") @After("pt1()") @Around
配置切入点表达式
@Pointcut("execution(* *.. *.*(..))")
private void pt1(){}
使用纯注解配置
//新建一个springConfig类
@Configuration //该注解表此类是spring配置类
@ComponentScan("com.baidu") //配置要扫描的包
@EnableAspectJAutoProxy //开aop支持
public class SpringConfiguration{
}
//需要改拿到容器的main方法ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfigration.class)
//此处写配置类的字节码文件
ICustomerService cs = (ICustomerService)ac.getBean("customerService")
cs.saveCustomer();




