目录
如何创建一个基础的Spring工程?
配置bean的注入方式:
bean配置的继承
使用bean的scope属性来配置bean的作用域
IOC容器中Bean的生命周期方法
配置AOP
使用注解进行增强配置:
如何创建一个基础的Spring工程?
1、先建立一个java工程
2、导入Spring所依赖的基础包:
- spring-aop-3.2.13.RELEASE.jar
- spring-beans-3.2.13.RELEASE.jar
- spring-context-3.2.13.RELEASE.jar
- spring-core-3.2.13.RELEASE.jar
3、创建xml文件(文件名:applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
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-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
</beans>
4、编写POJO
public class HelloWorld {
private String name;
public HelloWorld() {
System.out.println("HelloWorld无参构造器...");
}
public HelloWorld(String name) {
System.out.println("HelloWorld有参构造器...");
this.name = name;
}
public void setName(String name) {
System.out.println("setName方法...");
this.name = name;
}
public void hello(){
System.out.println("hello:"+name);
}
}
5、在配置文件中配置bean
<!--
配置bean
class: bean 的全类名,通过反射的方式在 IOC 容器中创建 bean,所以要求bean中必须有无参数的构造器
id: 标识容器中的bean,id唯一
-->
<bean id="helloWorld" class="com.self.spring.beans.HelloWorld">
<!--属性注入,通过bean的set方法
name为属性名,value为属性值-->
<property name="name" value="Spring11111"/>
</bean>
<bean id="helloWorld1" class="com.self.spring.beans.HelloWorld">
<!--构造器注入,通过bean的构造器
name为属性名,value为属性值-->
<constructor-arg name="name" value="Spring22222"/>
</bean>
6、在java中获取bean对象
//ApplicationContext :IOC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过beanId返回IOC容器中的Bean
HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld1");
//通过类型返回IOC容器中的Bean,但要求IOC容器中必须只能有一个该类型的Bean
// HelloWorld helloWorld1 = ctx.getBean(HelloWorld.class);
helloWorld.hello();
控制台结果>>
HelloWorld无参构造器...
setName方法...
HelloWorld有参构造器...
hello:Spring22222
配置bean的注入方式:
首先得有一个Car类,在配置文件中来配置bean
public class Car {
private String brand;
private String corp;
private double price;
private int maxSpeed;
public Car() {}
public Car(String brand, String corp, double price) {
this.brand = brand;
this.corp = corp;
this.price = price;
}
public Car(String brand, String corp, int maxSpeed) {
this.brand = brand;
this.corp = corp;
this.maxSpeed = maxSpeed;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void setCorp(String corp) {
this.corp = corp;
}
public void setPrice(double price) {
this.price = price;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", corp='" + corp + '\'' +
", price=" + price +
", maxSpeed=" + maxSpeed +
'}';
}
}
注入方式:
- 属性注入
- 构造器注入
- p命名空间注入
<bean id="car1" class="com.self.spring.beans.Car">
<!--name为构造器上的参数名,来定位构造器-->
<constructor-arg name="brand" value="大众"/>
<constructor-arg name="corp" value="上海"/>
<constructor-arg name="maxSpeed" value="200"/>
</bean>
<bean id="car2" class="com.self.spring.beans.Car">
<!--可以在type上写上参数类型,来定位重载构造器-->
<constructor-arg value="奔驰" index="0"/>
<constructor-arg value="上海" index="1"/>
<constructor-arg value="500000" type="double"/>
</bean>
<bean id="car3" class="com.self.spring.beans.Car">
<!--构造器与属性联用,用到属性的需要set方法-->
<constructor-arg name="brand" value="奥迪"/>
<constructor-arg name="corp" value="上海"/>
<constructor-arg name="maxSpeed" value="250"/>
<!--属性注入,通过bean的set方法,name为属性名,value为属性值-->
<property name="price" value="300000"/>
</bean>
<!-- 通过p命名空间来注入,实质是通过set方法来实现 -->
<bean id="car4" class="com.self.spring.beans.Car" p:brand="宝马" p:corp="德国" p:maxSpeed="250" />
还可以配置单例集合bean,以供多个bean进行引用,需要导入util命名空间
<util:list id="cars">
<ref bean="car1"/>
<ref bean="car2"/>
<ref bean="car3"/>
<ref bean="car4"/>
</util:list>
bean配置的继承
<!--
bean配置的继承
parent="父bean的id",子bean也可以覆盖继承后的属性值
abstract="true" 表示该bean为抽象bean,不能被实例化,用来当作模板。当bean中没有class属性时,abstract必须为true,只能当作模板
但abstract、autowire等属性不会被继承
-->
<bean id="AbstractCar" class="com.self.spring.beans.Car" p:brand="五菱宏光" abstract="true"/>
<bean id="car5" parent="AbstractCar" p:price="600000"/>
使用bean的scope属性来配置bean的作用域
<!--
什么是作用域,默认情况下在IOC容器中getbean("beanId")获得的是同一个对象,也就是说是单例的
可以通过修改scope属性来改变作用域
scope="singleton" 默认的
scope="prototype" 在IOC容器中getbean("beanId")时创建一个新的对象
-->
<bean id="car6" class="com.self.spring.beans.Car" p:brand="尼桑" p:corp="日本" />
<bean id="car7" class="com.self.spring.beans.Car" p:brand="BYD" p:corp="中国" scope="prototype"/>
IOC容器中Bean的生命周期方法
<!--
1、创建Bean,构造器
2、设置属性或对其他Bean的引用
3、调用Bean的初始化方法
4、Bean可以使用了
5、当容器关闭时调用Bean的销毁方法
-->
<!--在Bean的声明里设置init-method和destroy-method属性,为bean指定初始化和销毁方法,是单一的处理-->
<bean id="car8" class="com.self.spring.beans.Car" init-method="initfun" destroy-method="destroyfun"/>
<!--创建Bean后置处理器,bean后置处理器允许在调用初始化方法前后对bean进行额外的处理,对每个实例都会处理不是单一的处理-->
<!--实现BeanPortProcessor 接口,并为下面两方法具体提供方法体
1、public Object postProcessBeforeInitialization(Object bean, String beanName)在初始化方法前执行
2、初始化方法()
3、public Object postProcessAfterInitialization(Object bean, String beanName)在初始化方法后执行
将bean实例传给bean参数,beanName为IOC的beanId
-->
<!--配置bean后置处理器类-->
<bean class="com.self.spring.MyBeanPostProcessor.MyPostProcessor"/>
在bean中写上初始化方法、销毁方法,方法名应与该属性的值相同 init-method="initfun" destroy-method="destroyfun"
public class Car{
......
public void initfun(){
System.out.println("Car的初始化方法...");
}
public void destroyfun(){
System.out.println("Car的销毁方法...");
}
}
创建后置处理器,实现BeanPostProcessor接口
public class MyPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(bean+","+beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(bean+","+beanName);
return bean;
}
}
配置AOP
什么时候会应用到AOP技术呢?在代码需要扩展的时候,AOP技术可以在不修改源码的情况下进行增强处理
有一个这样的代码:
public class OldProcess {
public int oldProcessfun1(){
System.out.println("oldProcess程序(版本1.0)执行...");
//发生异常
/*int[] a = new int[1];
a[100] = 9;*/
return 1;
}
}
运行的代码
public static void main(String[] arg){
OldProcess oldProcess1 = (OldProcess) ctx.getBean("oldProcess1");
oldProcess1.oldProcessfun1();
}
当需要在 oldProcessfun1() 执行前想增加其他业务代码时,就可以配置前置增强:
1、创建含业务代码的类:
public class BeforeAspect {
public void beforeAspectfun(JoinPoint jp){
System.out.println("前置增强程序...");
}
}
2、在xml文件中进行AOP配置
<!-- AOP配置开始 -->
<!--切入点所对应的对象,必须在IOC容器中-->
<bean id="oldProcess1" class="com.self.spring.oldProcess.OldProcess"/>
<!-- 配置增强处理类的bean -->
<bean id="beforeAspect1" class="com.self.spring.aspect.BeforeAspect"/>
<aop:config>
<!-- 配置切入点
注意:切入点所对应的对象一定要是IOC容器中的Bean-->
<aop:pointcut id="pointCut1" expression="execution(public int oldProcessfun1())"/>
<!-- 配置切面 -->
<aop:aspect ref="beforeAspect1">
<!--前置增强,使beforeAspectfun方法在执行切入点方法前执行-->
<aop:before method="beforeAspectfun" pointcut-ref="pointCut1"/>
</aop:aspect>
</aop:config>
另外还有后置增强、最终增强、环绕增强、异常处理增强
xml配置:
<!-- AOP配置开始 -->
<!--切入点所对应的对象,必须在IOC容器中-->
<bean id="oldProcess1" class="com.self.spring.oldProcess.OldProcess"/>
<!-- 配置增强处理类的bean -->
<bean id="beforeAspect1" class="com.self.spring.aspect.BeforeAspect"/>
<bean id="afterAspect1" class="com.self.spring.aspect.AfterAspect"/>
<bean id="throwAspect1" class="com.self.spring.aspect.ThrowAspect"/>
<bean id="finallyAspect1" class="com.self.spring.aspect.FinallyAspect"/>
<bean id="aroundAspect1" class="com.self.spring.aspect.AroundAspect"/>
<aop:config>
<!-- 配置切入点
注意:切入点所对应的对象一定要是IOC容器中的Bean-->
<aop:pointcut id="pointCut1" expression="execution(public int oldProcessfun1())"/>
<!-- 配置切面 -->
<aop:aspect ref="beforeAspect1">
<!--前置增强,使beforeAspectfun方法在执行切入点方法前执行-->
<aop:before method="beforeAspectfun" pointcut-ref="pointCut1"/>
</aop:aspect>
<aop:aspect ref="afterAspect1">
<!--
后置增强,使afterAspectfun方法在执行切入点方法后执行,
并且afterAspectfun能够获取切入点方法的返回值,
0oldMethodResult为afterAspectfun方法的参数,用于接收切入点方法的返回值
-->
<aop:after-returning method="afterAspectfun" pointcut-ref="pointCut1" returning="oldMethodResult"/>
<!--注意:后置增强与环绕增强处理联用会使后置增强获取不到oldProcess程序的返回值,因为该返回值在环绕增强中接收了-->
</aop:aspect>
<aop:aspect ref="throwAspect1">
<!--异常处理增强,使throwAspectfun1方法在切入点执行发生错误时执行-->
<aop:after-throwing method="throwAspectfun1" pointcut-ref="pointCut1" throwing="excep"/>
</aop:aspect>
<aop:aspect ref="finallyAspect1" >
<!--最终增强处理-->
<aop:after method="finallyAspectfun1" pointcut-ref="pointCut1"/>
</aop:aspect>
<aop:aspect ref="aroundAspect1">
<!--环绕增强处理-->
<!-- <aop:around method="ArroundAspectMethod1" pointcut-ref="pointCut1"/>-->
</aop:aspect>
</aop:config>
java代码:
public class AfterAspect {
public void afterAspectfun(JoinPoint jp,Object oldMethodResult){
System.out.println("后置增强程序..."+"oldProcess的返回值:"+oldMethodResult);
}
}
public class FinallyAspect {
public void finallyAspectfun1(JoinPoint jp){
System.out.println("最终增强程序...");
}
}
public class AroundAspect {
public void ArroundAspectMethod1(ProceedingJoinPoint jp) {
try {
System.out.println("环绕处理增强,在oldProcess程序执行前执行...");
//以上代码相当与前置增强
Object ret = jp.proceed();//执行oldProcess程序
//以下代码相当与后置增强
System.out.println("环绕处理增强,在oldProcess程序执行后执行..."+"oldProcess的返回值:"+ret);
} catch (Throwable throwable) {
//相当与异常处理增强
System.out.println("环绕处理增强,在oldProcess程序执行异常时执行...");
throwable.printStackTrace();
} finally {
//相当与最终增强
System.out.println("环绕处理增强,在oldProcess程序执行无论报不报异常都执行...");
}
}
}
public class ThrowAspect {
public void throwAspectfun1(JoinPoint jp, Exception excep){
System.out.println("异常发生后执行的代码...");
}
}
使用注解进行增强配置:
xml文件配置:
<!--开启AOP注解支持-->
<aop:aspectj-autoproxy/>
<!--配置使用注解的类-->
<bean class="com.self.spring.aspectUseAnnotation.AspectAnnotation"/>
<!--开启注解所在的包的扫描-->
<context:component-scan base-package="com.self.spring.aspectUseAnnotation"/>
java代码:
@Aspect
public class AspectAnnotation {
/**
* 前置增强
* @param jp
*/
@Before("execution(public int oldProcessfun1())")
public void beforeMethod(JoinPoint jp){
System.out.println("注解实现前置增强程序...");
}
/**
* 异常处理增强
* @param jp
* @param e
*/
@AfterThrowing(pointcut = "execution(public * oldProcessfun1())",throwing="e")
public void throwMethod(JoinPoint jp,Exception e){
System.out.println("注解实现异常处理增强程序...");
}
/**
* 最终增强
* @param jp
*/
@After("execution(public * oldProcessfun1())") //相当于配置了切入点、
public void afterMethod(JoinPoint jp){
System.out.println("注解实现最终增强程序...");
}
/**
* 后置增强,与环绕增强处理联用会使后置增强获取不到oldProcess程序的返回值,因为该返回值在环绕增强中接收了
* @param jp
*/
@AfterReturning(pointcut = "execution(public * oldProcessfun1())",returning = "ret")
public void afterReturnMethod(JoinPoint jp ,Object ret) {
System.out.println("注解实现后置增强程序..."+"oldProcess的返回值:"+ret);
}
/**
* 环绕增强
*/
// @Around("execution(public * oldProcessfun1())")
public void aroundMethod(ProceedingJoinPoint jp) {
try {
System.out.println("注解实现环绕处理增强,在oldProcess程序执行前执行...");
//以上代码相当与前置增强
Object ret = jp.proceed();//执行oldProcess程序
//以下代码相当与后置增强
System.out.println("注解实现环绕处理增强,在oldProcess程序执行后执行..."+"oldProcess的返回值:"+ret);
} catch (Throwable throwable) {
//相当与异常处理增强
System.out.println("注解实现环绕处理增强,在oldProcess程序执行异常时执行...");
throwable.printStackTrace();
} finally {
//相当与最终增强
System.out.println("注解实现环绕处理增强,在oldProcess程序执行无论报不报异常都执行...");
}
}
}