Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架
Spring的核心jar包
spring-framework-3.2.0.RELEASE-dist.zip -------Spring的核心包
spring-framework-3.0.2.RELEASE-dependencies.zip ------ Spring的依赖包
spring-core-3.2.2.RELEASE.jar: 包含Spring框架基本的核心工具类,Spring其它组件要都要使用到这个包里的类,是其它组件的基本核心 |
|
spring-beans-3.2.2.RELEASE.jar: 包含访问配置文件、创建和管理bean 以及进行Inversion of Control(IoC) / Dependency Injection(DI)操作相关的所有类 |
|
spring-expression-3.2.2.RELEASE.jar Spring表达式语言 |
|
spring-context-3.2.2.RELEASE.jar Spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持, 如邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等 |
|
|
IOC&&DI
IOC控制反转的概念,就是将原本在程序中手动创建对象的控制权,交由Spring框架管理,即创建对象控制权被反转到了Spring框架
DI 依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件
BeanFactory && ApplicationContext
BeanFactory 才是 Spring 容器中的顶层接口。
ApplicationContext 是它的子接口。
区别:
ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
BeanFactory:什么使用什么时候创建对象
bean标签
作用:
用于配置对象让 spring 来创建的。
默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
属性:
id: 给对象在容器中提供一个唯一标识。用于获取对象。
class: 指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
scope: 指定对象的作用范围。
* singleton :默认值,单例的.
* prototype :多例的.
* request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
* session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
* global session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么
globalSession 相当于 session.
init-method: 指定类中的初始化方法名称。
destroy-method: 指定类中销毁方法名称。
实例化bean的三种方式
使用构造方法实例化
1 使用默认无参构造函数 2 3 根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败 4 5 <bean id="accountService" class="com.xxx.service.impl.AccountServiceImpl"/>
使用静态工厂实例化
1 /** 2 * 模拟一个静态工厂,创建业务层实现类 3 */ 4 public class StaticFactory { 5 public static IAccountService createAccountService(){ 6 return new AccountServiceImpl(); 7 } 8 } 9 10 <!-- 此种方式是: 11 使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器 12 id 属性:指定 bean 的 id,用于从容器中获取 13 class 属性:指定静态工厂的全限定类名 14 factory-method 属性:指定生产对象的静态方法 15 --> 16 <bean id="accountService" 17 class="com.xxx.factory.StaticFactory" 18 factory-method="createAccountService"></bean>
使用实例工厂方法实例化
1 /** 2 * 模拟一个实例工厂,创建业务层实现类 3 * 此工厂创建对象,必须现有工厂实例对象,再调用方法 4 */ 5 public class InstanceFactory { 6 public IAccountService createAccountService(){ 7 return new AccountServiceImpl(); 8 } 9 } 10 <!-- 此种方式是: 11 先把工厂的创建交给 spring 来管理。 12 然后在使用工厂的 bean 来调用里面的方法 13 factory-bean 属性:用于指定实例工厂 bean 的 id。 14 factory-method 属性:用于指定实例工厂中创建对象的方法。 15 --> 16 <bean id="instancFactory" 17 class="com.xxx.factory.InstanceFactory"></bean> 18 <bean id="accountService" 19 factory-bean="instancFactory" 20 factory-method="createAccountService"></bean>
Spring依赖注入方式
构造函数注入
1 public class AccountServiceImpl implements IAccountService { 2 private String name; 3 private Integer age; 4 private Date birthday; 5 public AccountServiceImpl(String name, Integer age, Date birthday) { 6 this.name = name; 7 this.age = age; 8 this.birthday = birthday; 9 } 10 // 11 12 } 13 14 15 <!-- 16 17 constructor-arg 18 属性: 19 index:指定参数在构造函数参数列表的索引位置 20 type:指定参数在构造函数中的数据类型 21 name:指定参数在构造函数中的名称 22 value:它能赋的值是基本数据类型和 String 类型 23 ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean 24 --> 25 26 <bean id="accountService" class="com.xxx.service.impl.AccountServiceImpl"> 27 <constructor-arg name="name" value="张三"></constructor-arg> 28 <constructor-arg name="age" value="18"></constructor-arg> 29 <constructor-arg name="birthday" ref="now"></constructor-arg> 30 </bean> 31 <bean id="now" class="java.util.Date"></bean>
Set方法注入‘
1 public class User { 2 private String username; 3 private String password;
4 public String getUsername() { 5 return username; 6 } 7 public void setUsername(String username) { 9 this.username = username; 10 } 11 public String getPassword() { 12 return password; 13 } 14 public void setPassword(String password) { 15 this.password = password; 16 } 17 18 19 } 20 <!----
name:找的是类中 set 方法后面的部分
ref:给属性赋值是其他 bean 类型的
value:给属性赋值是基本数据类型和 string 类型的
----> 21 22 23 24 <bean id = "user" class= "com.xxx.model.User"> 25 <property name="username" value="gyf"></property> 26 <property name="password" value="123"></property> 27 28 </bean>
集合注入
也是set的注入方式
集合的注入都是给<property>添加子标签
数组:<array>
List:<list>
Set:<set>
Map:<map> ,map存放k/v 键值对,使用<entry>描述
Properties:<props> <prop key=""></prop> 【】
普通数据:<value>
引用数据:<r 1 public class Programmer {
2 3 private List<String> cars; 4 5 private Set<String> pats; 6 7 private Map<String,String> infos; 8 9 private Properties mysqlInfos; 10 11 private String[] members; 12 //setter getter 13 14 } 15
<!-- 注入集合数据
List 结构的:
array,list,set
Map 结构的
map,entry,props,prop
-->
16 <bean id="programmer" class="com.xxx.model.Programmer"> 17 <property name="cars"> 18 <!-- list数据的注入 --> 19 <list> 20 <value>offo</value> 21 <value>mobai</value> 22 </list> 23 </property> 24 25 26 <property name="pats"> 27 <set> 28 <value>猫</value> 29 <value>狗</value> 30 </set> 31 </property> 32 33 <!-- Map数据的注入 --> 34 <property name="infos"> 35 <map> 36 <entry key="name" value="gyf"></entry> 37 <entry key="age" value="12"></entry> 38 <entry key="ip" value="127.0.0.1"></entry> 39 </map> 40 </property> 41 42 43 <!-- Properties属性注入 --> 44 <property name="mysqlInfos"> 45 <props> 46 <prop key="url">mysql:jdbc://localhost:3306/dbname</prop> 47 <prop key="user">root</prop> 48 <prop key="password">root</prop> 49 </props> 50 </property> 51 52 53 54 55 <!-- 数组参数注入 --> 56 <property name="members"> 57 <array> 58 <value>哥哥</value> 59 <value>弟弟</value> 60 <value>妹妹</value> 61 </array> 62 </property> 63 64 65 </bean>
注解注入
注解:就是一个类,使用@注解名称
开发中:使用注解 取代 xml配置文件。
1 @Component 2 @component取代<bean class=""> 3 4 5 @Component("id") 取代 <bean id="" class=""> 6 7 8 @Repository(“”):dao层 9 @Service(“”):service层 10 @Controller(“”):web层 11 12 @Autowired:自动根据类型注入 @Qualifier(“”):指定自动注入的id名称 13 @Resource(“名称”) 14 15 @ PostConstruct 自定义初始化 16 @ PreDestroy 自定义销毁
Aop
面向切面编程。
作用:
在程序运行期间,不修改源码对已有方法进行增强。
优势:
减少重复代码
提高开发效率
维护方便
术语
target:目标类,需要被代理的类。例如:UserService Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法 PointCut 切入点:已经被增强的连接点。例如:addUser() advice 通知/增强,增强代码。例如:after、before Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程. proxy 代理类
Aspect(切面): 是切入点pointcut和通知advice的结合 一个线是一个特殊的面。 一个切入点和一个通知,组成成一个特殊的面。
jdk动态代理&&cglib动态代理
基于接口的动态代理
提供者: JDK 官方的 Proxy 类。
要求:被代理类最少实现一个接口。
基于子类的动态代理
提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。
要求:被代理类不能用 final 修饰的类(最终类)。
通知
•前置通知 org.springframework.aop.MethodBeforeAdvice
•在目标方法执行前实施增强
•后置通知 org.springframework.aop.AfterReturningAdvice
•在目标方法执行后实施增强
•环绕通知 org.aopalliance.intercept.MethodInterceptor
•在目标方法执行前后实施增强
•异常抛出通知 org.springframework.aop.ThrowsAdvice
•在方法抛出异常后实施增强
•引介通知 org.springframework.aop.IntroductionInterceptor
在目标类中添加一些新的方法和属性
1 环绕通知,必须手动执行目标方法 2 3 try{ 4 //前置通知 5 //执行目标方法 6 //后置通知 7 } catch(){ 8 //抛出异常通知 9 }
Aop配置
1 IAccountService 2 3 AccountServiceImpl 4 5 <!-- 配置srping的Ioc,把service对象配置进来--> 6 <bean id="accountService" class="com.xxx.service.impl.AccountServiceImpl"></bean> 7 8 9 <!--spring中基于XML的AOP配置步骤 10 1、把通知Bean也交给spring来管理 11 2、使用aop:config标签表明开始AOP的配置 12 3、使用aop:aspect标签表明配置切面 13 id属性:是给切面提供一个唯一标识 14 ref属性:是指定通知类bean的Id。 15 4、在aop:aspect标签的内部使用对应标签来配置通知的类型 16 我们现在示例是让printLog方法在切入点方法执行之前之前:所以是前置通知 17 aop:before:表示配置前置通知 18 method属性:用于指定Logger类中哪个方法是前置通知 19 pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强 --> 20 <!-- 配置Logger类,切面类 --> 21 <bean id="logger" class="com.itheima.utils.Logger"></bean> 22 23 <!--配置AOP--> 24 <aop:config> 25 <!--配置切面 --> 26 <aop:aspect id="logAdvice" ref="logger"> 27 <!-- 配置通知的类型,并且建立通知方法和切入点方法的关联--> 28 <aop:before method="printLog" pointcut="execution(* com.itheima.service.impl.*.*(..))"></aop:before> 29 </aop:aspect> 30 </aop:config>
切入点表达式的写法:
关键字:execution(表达式)
表达式:
访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表)
public void com.xxx.service.impl.AccountServiceImpl.saveAccount()
访问修饰符可以省略 void com.xxx.service.impl.AccountServiceImpl.saveAccount()
返回值可以使用通配符 * ,表示任意返回值
包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
* * .* .*. *. AccountServiceImpl.saveAccount())
包名可以使用..表示当前包及其子包
* *. . AccountServiceImpl.saveAccount()
类名和方法名都可以使用*来实现通配
* *. . * . * ()
参数列表:
可以直接写数据类型:
基本类型直接写名称 int
引用类型写包名.类名的方式 java.lang.String
可以使用通配符表示任意类型,但是必须有参数
可以使用 . . 表示有无参数均可,有参数可以是任意类型
() 无参
(int) 一个整型
(int ,int) 两个
(..) 参数任意
全通配写法:
* *. .*.*(. .)
通常写法:切到业务层实现类下的所有方法
* com.xxx.service.impl.*.*(..)
基于注解的aop
bean.xml
1 <!-- 配置spring创建容器时要扫描的包--> 2 <context:component-scan base-package="com.xxx"></context:component-scan> 3 4 <!-- 配置spring开启注解AOP的支持 --> 5 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
替换service和切面bean
@Service
@Component
@Aspect//表明当前类是一个切面类
在增强的方法上使用注解配置通知
@Before
作用:
把当前方法看成是前置通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
@Before("execution(* com.xxx.service.impl.*.*(..))")
@AfterReturning 把当前方法看成是后置通知。
@Around :把当前方法看成是环绕通知
@Pointcut 指定切入点表达式
1 @Aspect 声明切面,修饰切面类,从而获得 通知。 2 3 @Before 前置 4 5 @AfterReturning 后置 6 7 @Around 环绕 8 9 @AfterThrowing 抛出异常 10 11 @After 最终 12 13 切入点 @PointCut ,修饰方法 private void xxx(){} 之后通过“方法名”获得切入点引用
完