控制反转
在spring中我们使用applicationContext.xml文件来进行管理bean
就是将原本在程序中手动创建HelloService对象的控制权,交由Spring框架管理,简单说,就是创建HelloService对象控制权被反转到了Spring框架;
读取核心配置文件方式
ApplicationContext 应用上下文,加载Spring 框架配置文件
加载classpath:(这种方法常用)
new ClassPathXmlApplicationContext("applicationContext.xml");
加载磁盘路径:
new FileSystemXmlApplicationContext(磁盘路径+"applicationContext.xml");
三种实例化Bean的方式
1.使用类构造器实例化(默认无参数)(推荐) <bean id=“personService" class=“com.jiyun.bean.impl.PersonServiceImpl"/>
2.使用静态工厂方法实例化(简单工厂模式) <bean id="personService" class="com..jiyun.factory.PersonServiceFactory" factory-method="createPersonService" /> public class PersonServiceFactory { public static PersonService createPersonService(){ return new PersonServiceImpl(); } }
3.使用实例工厂方法实例化(工厂方法模式): <bean id=“personServiceFactory" class="com.jiyun.factory.PersonServiceFactory"/> <bean id="personService" factory-bean=“personServiceFactory" factory-method="createPersonService" />
factory-method是你写的实体类中的
Bean的作用域
类别 |
说明 |
singleton |
在Spring IoC容器中仅存在一个Bean实例,Bean以单例方式存在 |
prototype |
每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean() |
request |
每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session |
同一个HTTP Session 共享一个Bean,不同Session使用不同Bean,仅适用于WebApplicationContext 环境 |
globalSession |
一般用于Porlet应用环境,该作用域仅适用于WebApplicationContext 环境 |
singleton: 单例,默认spring 容器实例的bean为单例;
prototype:多例
Spring容器的生命周期
Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法。
<bean id=“foo” class=“...Foo” init-method=“setup” destory-method=“teardown”/>
当bean被载入到容器的时候调用setup
当bean从容器中删除的时候调用teardown(scope= singleton有效)
依赖注入Bean的属性
构造函数注入
属性setter方法注入
接口注入
Spring支持前两种,依赖注入是单独的一种技术
<!-- 构造方法注入 --> <bean id="u1" class="com.jy.bean.User"> <constructor-arg index="0" type="java.lang.Integer" value="10"/> <constructor-arg index="1" type="java.lang.String" value="王五"/> </bean> <!-- 构造方法注入 --> <bean id="u1" class="com.jy.bean.User"> <constructor-arg index="0" type="java.lang.Integer" value="10"/> <constructor-arg index="1" type="java.lang.String" value="王五"/> </bean>
• 属性setter方法注入(推荐)
使用多个XML配置文件
方式一 :可以在创建ApplicationContext对象时传入多个配置文件
ApplicationContext applicationContext = new
ClassPathXmlApplicationContext("beans1.xml", "beans2.xml");
方式二 :可以在配置文件中通过<import>引入其他配置文件(推荐)
<import resource="classpath:bean2.xml"/>
注解
javaSE:
方法重写@Override 校验子类重写父类的方法声明是否与父类完全相同;
注解基本作用:为了取代配置文件,实现零配置;
通过注解可以屏蔽配置文件内容过多,不易维护问题;
注解不能实现插拔功能:因为注解是写在java源码中的
使用注解定义Bean 类基本注解
除了@Component外,Spring提供了3个功能基本和@Component等效的注解
@Repository 用于对DAO持久层实现类进行标注
@Service 用于对Service服务层实现类进行标注
@Controller 用于对Controller控制层实现类进行标注
这三个注解是为了让标注类本身的用途清晰,Spring在后续版本会对其增强
//@Component(value="user") //相等于<bean id="user" class="com.jy.bean.User"/>
//@Component //如果不给类起名,默认使用的是类名首字母小写
@Component("user") //如果注解中只有一个属性值,可以不写属性名称
public class User {
@Value(value="李四") //<property name="uname" value="张三"/>
private String uname; //@Component(value="user") //相等于<bean id="user" class="com.jy.bean.User"/>
自动装配Bean 属性级别注解
使用@Autowired 进行自动注入
@Service 标注业务类
@Repository 标注DAO
@Autowired 默认按照类型进行注入
如果存在两个相同Bean类型相同,则按照名称注入
@Autowired注入时可以针对成员变量或者setter方法
UserService.java
package com.zym.service; import com.zym.dao.UserDaoInf; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService implements UserServiceInf{ @Autowired private UserDaoInf daoInf; @Override public void selectUser() { daoInf.selectAll(); } }
UserDao.java
package com.zym.dao; import org.springframework.stereotype.Repository; @Repository public class UserDao implements UserDaoInf { public void selectAll(){ System.out.println("select all success"); } }
测试
@Test public void test1() { ClassPathXmlApplicationContext cpac = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService ser= cpac.getBean("userService", UserService.class);//这个地方默认小写开头, ser.selectUser(); }
通过名称注入
通过@Autowired的required属性,设置一定要找到匹配的Bean
使用@Qualifier指定注入Bean的名称
使用Qualifier 指定Bean名称后,注解Bean必须指定相同名称
@Resource
java本身带的
Spring提供对JSR-250中定义@Resource标准注解的支持
@Resource和@Autowired注解功能相似
Bean的初始化
User.java
@Component public class User { private String name; private Integer age; public User(String name, Integer age) { this.name = name; this.age = age; } public User() { } @PostConstruct public void init(){ System.out.println("初始化"); } @PreDestroy public void destory(){ System.out.println("销毁"); }
测试
@Test public void test2() { ClassPathXmlApplicationContext a = new ClassPathXmlApplicationContext("applicationContext.xml"); // Object user = a.getBean("user"); a.close(); }
相当于
Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法。 <bean id=“foo” class=“...Foo” init-method=“setup” destory-method=“teardown”/>
Bean的作用域范围
@Scope注解用于指定Bean的作用范围
Bean的初始化(使用javaconfig来进行配置bean)
Spring3.0以JavaConfig为核心,提供使用Java类定义Bean信息的方法
@Configuration 指定POJO类为Spring提供Bean定义信息
@Bean 提供一个Bean定义信息
UserDaoInf.java
public interface UserDaoInf { public void selectAll(); }
UserDao.java
package com.zym.dao; import org.springframework.stereotype.Repository; @Repository public class UserDao implements UserDaoInf { public void selectAll(){ System.out.println("select all success"); } }
在跟你的dao层平级创建一个config,在下面创建如下文件
package com.zym.config; import com.zym.dao.UserDao; import com.zym.dao.UserDaoInf; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class UserDaoConfig { @Bean public UserDaoInf getUserDao(){ return new UserDao(); } @Bean(name="getUserDao2xxx") public UserDaoInf getUserDao2(){ return new UserDao(); } }
测试
@Test public void test1() { ClassPathXmlApplicationContext cpac = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao xxx = cpac.getBean("getUserDao",UserDao.class); xxx.selectAll(); }
代理模式
目的:为目标对象增强功能;
代码执行,为纵向执行 ,从上到下执行;
静态代理
主类
package com.jy.proxy; //厂家 目标对象 public class Factory implements PublicInf{ @Override public void computerList() { //介绍电脑 System.out.println("电脑系列!!!"); //买电脑福利 } }
代理类
package com.jy.proxy; //代理对象 代理商 public class MyProxy implements PublicInf { private PublicInf inf; public MyProxy(PublicInf inf) { super(); this.inf = inf; } // 代理的实现时调用厂家的功能 @Override public void computerList() { //介绍电脑 this.introduc(); inf.computerList(); //买电脑福利 this.gift(); } //介绍电脑 public void introduc(){ System.out.println("吹吹电脑有多牛!"); } //买电脑福利 public void gift(){ System.out.println("免费送货。。。"); } }
接口规范类
package com.jy.proxy; //目标对象和代理对象的公共功能 public interface PublicInf { //电脑系列 public void computerList(); }
测试类
package com.jy.proxy; public class Main { public static void main(String[] args) { // 从代理买电脑 PublicInf inf = new Factory(); MyProxy pro = new MyProxy(inf); pro.computerList(); } }
aop开发案例
beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 配置业务 --> <bean id="target" class="com.zym.aop.BookBizImpl" /> <!-- 日志方面 --> <bean id="log" class="com.zym.aop.LogAdvice" /> <bean id="gift" class="com.zym.aop.GiftAdvice"/> <!-- 组装 --> <bean id="bookbiz" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"><!-- 业务接口 --> <value>com.zym.aop.BookBizInf</value> </property> <property name="interceptorNames"><!-- 切面 --> <list> <value>log</value> <value>gift</value> </list> </property> <property name="target" ref="target"/><!-- 业务实现 --> </bean> </beans>
BookBizInf.java
package com.zym.aop; public interface BookBizInf { //买书 public void buy(String uname, String bname, int price); //书评 public void comment(String uname, String comments); }
BookBizImpl.java
package com.zym.aop; //业务逻辑,商业逻辑 public class BookBizImpl implements BookBizInf { // 买书 public void buy(String uname, String bname, int price) { System.out.println("方法buy开始执行,"); System.out.println("用户:"+uname+",买了一本:"+bname+",积分增加:"+price); System.out.println("方法buy执行结束。"); } // 书评 public void comment(String uname, String comments) { System.out.println("方法comment开始执行,"); System.out.println("用户:"+uname+",发布书评:"+comments); System.out.println("方法comment执行结束。"); } }
GiftAdvice.java
package com.zym.aop; import java.lang.reflect.Method; import java.util.Arrays; import org.springframework.aop.AfterReturningAdvice; //后置通知 public class GiftAdvice implements AfterReturningAdvice{ @Override public void afterReturning(Object arg0, Method m, Object[] objs, Object arg3) throws Throwable { System.out.println("执行的方法为:"+m.getName()+",参数:"+Arrays.toString(objs)+",返现金为:¥88.00"); } }
LogAdvice.java
package com.zym.aop; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Date; import org.springframework.aop.MethodBeforeAdvice; //前置通知 public class LogAdvice implements MethodBeforeAdvice{ @Override public void before(Method m, Object[] objs, Object arg2) throws Throwable { System.out.println("【日志】方法:"+m.getName()+",执行时间为:"+new Date()+",参数:"+Arrays.toString(objs)); } }
测试
package com.zym.aop; import org.testng.annotations.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class BookAopTest { @Test public void test() { //获得spring容器对象 ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml"); //获得代理对象 BookBizInf bz = ac.getBean("bookbiz", BookBizInf.class); bz.buy("张三", "葫芦娃", 10); bz.comment("李四", "开发书真贵!"); } }
aop术语
- 连接点(Joinpoint)
程序运行过程中,JVM负责程序运行。执行到某个方法时,JVM能识别当前执行的是哪个方法。这些定义在类中的方法,每个具有独立的功能,在AOP中,将这些具有特定功能的方法称为连接点。
- 切入点(Pointcut)
类中的方法具有很多,某些方法具有一些共同的流程,例如数据库连接的获取与关闭,事务的开启与提交,等等。将这些公共的特性抽取出来,抽取完毕后,原始方法中就缺少了这些被抽取的代码。在实际运行时,缺少这些代码是无法完成原始的功能的。这些被抽取了公共功能的方法称为切入点
切入点一定是连接点,连接点不一定是切入点
切入点指被抽取了共性功能的方法分
- 通知(Advice)
切入点对应的方法的共性功能被抽取后,组成独立代码逻辑,被封装在某个类的某个方法中,在被抽取了共性功能的方法被执行时,这些代码逻辑还要加入原始方法的执行,这些被抽取出来组成独立代码逻辑的共性功能称为通知
- 引入(Introduction)
通知仅表示切入点被抽取的代码逻辑,对于切入点所在的类,如果存在有共性的成员变量或者成员方法,通知将无法进行描述。AOP提供引入机制,将共性功能的成员进行加入。
引入机制可以为类添加额外的成员变量或者成员方法
引入机制是在编译期或类加载期完成的
- 目标对象(Target Object)
被代理创建的对象,称为目标对象
- AOP代理(AOP Proxy)
切入点所在的类对象执行切入点方法时,需要将原始的共性功能(通知)加入,此时通过代理的形式创建类对象,并完成共性功能(通知)的加入,上述过程称为AOP代理
- 织入(Weaving)
通过AOP代理,完成了切入点与通知的融合,并组成了完整的代码逻辑,将通知加入到切入点对应位置的动作称为织入
- 切面(Aspect)
切面是一个设计概念,指切入点与通知的匹配模式,换句话说指被抽取了共性功能的方法(切入点)与被抽取的共性功能(通知)对应的绑定关系
execution
AOP切入点表达式支持多种形式的定义规则 execution:匹配方法的执行(常用) execution(public * *(..)) within:匹配包或子包中的方法(了解) within(com.jy.aop..*) this:匹配实现接口的代理对象中的方法(了解) this(com.jy.aop.user.UserDAO) target:匹配实现接口的目标对象中的方法(了解) target(com.jy.aop.user.UserDAO) args:匹配参数格式符合标准的方法(了解) args(int,int) 匹配方法的执行(常用) 格式:execution(方法格式表达式) 例一:匹配所有指定返回值类型的方法 void *(..) int *(..) double *(..) 例二:匹配指定包或子包中类的方法 *..*() com.jy.aop.user.dao.*.*(..) cn..dao.*.*(..) 例三:匹配指定类或接口的方法 * *..UserImpl.*(..) * *..*Impl.*(..) * *..*DAO.*(..) 例四:匹配指定方法名或部分匹配方法名的方法 *..*.add(..) *..*.*e*(..) *..*.get*(..) 例五:匹配所有指定参数个数或类型的方法 * *..*.*(int,int) * *..*.*(*,*)