1、设值注入
2、构造注入
UserServiceImpl.java
public class UserServiceImpl implements UserService {
private UserDao userDao;
//无参构造
public UserServiceImpl{}
//带参构造
public UserServiceImpl(UserDao userDao){
this.userDao=userDao;
}
public void setuDao( UserDao uDao) {
this.uDao = uDao;
}
}
applicationContext.xml
注:
(1) 一个元素表示构造方法的一个参数,且使用时不区分顺序,当构造方法的参数出现混淆无法区分时,可以通过的index属性指定该参数位置索引,位置从0开始,type属性用来指定参数的类型,避免字符串与基本数据类型的混淆。
(2) 构造注入的时效性好,在对象实例化时就得到所依赖的对象, 便于在对象的初始方法中使用依赖对象;但受限于方法重载的形式,使用灵活性不足。设值注入使用灵活,但时效性不足,并有大量的getter/setter访问器增加了类的复杂性,Spring并不倾向于某种方式,根据情况选择。
3、使用p命名空间实现属性注入
p命名空间特点:
使用属性而不是子元素的形式配置Bean的属性,从而简化了Bean的配置。
例: 使用传统的
子元素配置的代码如下
Greeting.java
public class Greeting {
private String person;
private String words;
public String getPerson() {
return person;
}
public void setPerson(String person) {
this.person= person;
}
public String getWords() {
return words;
}
public void setWords(String words) {
this.words = words;
}
public Greeting(String person,String words){
this.person=person;
this.words=words;
}
public Greeting(){}
public void say(){
System.out.println(this.name+"说:"+this.words);
}
}
applicationContext.java
张嘎
三天不打鬼子,手都痒痒!
使用p命名空间实现属性注入
注:
(1)对于直接量(基本数据类型、字符串)属性,使用方式如下
(2)对于引用Bean的属性
4、注入不同数据类型
(1)注入直接量(基本数据类型、字符串)
注: 如果属性值中包含了XML的特殊字符(<、>、&、’、"),则注入时需要进行处理,通常采用两种方式:
第一种:使用,
如
第二种:把特殊字符替换为实体引用,如
在XML中5个预定义的实体引用:
(2)引用其他Bean组件
直接使用ref属性
例:
使用ref子元素的bean属性:
例:
注:ref元素中的bean属性指定要引用bean的id
注:local属性与bean属性都是指定要引用的bean的id,区别在于Spring配置是可拆分的;而使用local属性只能在同一个配置文件中检索bean的id,而使用bean属性可以在其他配置文件中检索id。
(3)使用内部Bean
注:此方式适用于该bean组件仅在一处使用
(4)注入集合类型的属性
例:
足球
篮球
注: 标签中可以使用、等标签注入集合元素
例:
足球
篮球
例:
**注:**如果map中的键或值是Bean对象,可以将
更改为
例:
足球
篮球
注: Properties中的键和值通常都为字符串类型
(5)注入null和空字符串值
1、异常抛出增强
特点: 在目标方法抛出异常时织入增强处理。使用异常抛出增强,可以为各功能模块提供统一的、可拔插的异常处理方案。
注: 使用
元素可定义异常抛出,可以为增强方法声明相关类型的参数,并通过throwing属性指定该参数名称,Spring会为其注入从目标方法抛出的异常实例。
例:
2、最终增强
3、环绕增强
元素可以定义环绕增强。通过为增强方法声明ProceedingJoinPoint 类型的参数,可以获得连接点信息,所用方法与JoinPoint 相同。ProceedingJoinPoint 是JoinPoint 的子接口,其不但封装目标方法及其入参数组,还封装了被代理的目标对象,通过它的proceed() 方法可以真正的调用目标方法,从而达到对连接点的完全控制。1、使用注解定义Bean
代码如下:
//通过注解定义了一个名称为userDao的对象
@Component("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void save(User user) {
System.out.println("保存用户信息");
}
}
注:
(1)@Component("userDao")
等效xml配置文件中的
(2)除了@Component
,spring还提供了3个特殊的注解
@Repository
用于标注DAO类@Service
用于标注业务类@Controller
用于标注控制器类2、使用注解实现Bean组件装配
/* 声明接口类型的引用和具体实现类解耦合 ,使用@Autowired为dao属性
注入所依赖的对象,Spring将直接对dao属性进行赋值
*/
@Autowired
private UserDao uDao; //用户dao
(1)若容器中有一个以上类型相匹配的Bean组件时,则可以使用@Qualifier指定所需要的Bean的名称。
@Autowired
@Qualifier("userDao")
private UserDao uDao; //用户dao
(2)@Autowired
注解也可以对方法的入参进行标注
@Autowired
public void setuDao(@Qualifier("userDao") UserDao uDao) {
this.uDao = uDao;
}
(3)也可用于构造方法,实现构造注入
//带参构造
@Autowired
public UserServiceImpl(@Qualifier("userDao")UserDao uDao){
this.uDao=uDao;
}
(4)使用@Autowired
注解进行装配时,如果找不到相匹配的Bean组件,Spring容器会抛出异常,此时如果依赖不是必须的,为避免抛出异常,可以将required属性设置为false。required默认为true,即必须找到匹配的 Bean完成装配,否则抛出异常。
@Autowired(required=false)
@Qualifier("userDao")
private UserDao uDao; //用户dao
(5)如果对类中集合类型的成员变量或方法入参使用@Autowired
注解,Spring容器会将所有和集合中元素类型匹配的Bean组件都注入进来。
public class TackQueue{
@Autowired(required=false)
private List toDoList;
}
注: Spring会将Job类型的Bean组件都注入给toDoList属性
3、加载注解定义的Bean
//在Spring配置文件中添加对context命名空间的声明
注:base-package属性指定了需要扫描的基准包,多个包名以逗号隔开;Spring会扫描这些包中的类,获取Bean的定义信息。
4、使用Java标准注解完成装配
//为dao属性注入名为userDao的Bean
@Resource(name="userDao")
private UserDao uDao; //用户dao
@Resource
注解将根据字段名或者setter方法名产生的默认名称; 如果注解应用于字段,将使用字段名作为Bean的名称。 //查找名为uDao的Bean,并注入给uDao属性
@Resource
private UserDao uDao; //用户dao
//查找名为uDao的Bean,并注入给setter方法
@Resource
public void setuDao( UserDao uDao) {
this.uDao = uDao;
}
@Resource
注解会由按名称查找的方式自动变为按类型匹配的方式进行装配。1、AspectJ简介
2、使用注解标注切面
@Aspect
public class UserServiceLogger {
//省略
}
@Before("execution(* cn.bdqn.service.UserService.*(..))")
public void before(JoinPoint jp){
System.out.println("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法入参:"
+Arrays.toString(jp.getArgs()));
}
//代表后置增强的方法
@AfterReturning(pointcut="execution(* cn.bdqn.service.UserService.*(..))",
returning="returnValue")
public void afterReturning(JoinPoint jp,Object returnValue){
System.out.println("调用"+jp.getTarget()+"的"+jp.getSignature().getName()
+"方法。方法返回值:"+returnValue);
}
注:
(1)对于后置增强,还可以定义一个参数用于接收目标方法的返回值,需要注意的是,必须在@AfterReturning
注解中通过returning属性指定该参数的名称,Spring会将目标方法的返回值赋值给指定名称的参数。
2)对于切入点相同的情况,可以定义切入点复用。切入点表达式使用@Pointcut注解来表示,而切入点签名则需通过一个普通的方法定义来提供,作为切入点签名的方法必须返回void类型,切入点定义后,就可以使用“pointcut()”切面进行使用。
例:
@Pointcut("execution(* cn.bdqn.service.UserService.*(..))")
public void pointcut(){}
@Before("pointcut()") //前置增强处理,引用定义好的切入点
public void before(JoinPoint jp){
System.out.println("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法入参:"
+Arrays.toString(jp.getArgs()));
}
(3)切面定义完成后,还需要在Spring配置文件中完成织入工作
//引入aop命名空间
3、使用注解定义其他类型的增强
/**
* 通过注解实现异常抛出增强
*/
@Aspect
public class ErrorLogger {
private static final Logger log=Logger.getLogger(ErrorLogger.class);
@AfterThrowing(pointcut="execution(* cn.bdqn.service.UserService.*(..))",
throwing="e")
public void afterThrowing(JoinPoint jp,RuntimeException e){
log.error(jp.getSignature().getName()+"方法有异常"+e);
}
}
/**
* 使用注解实现最终增强
* @author 14062
*
*/
@Aspect
public class AfterLogger {
private static final Logger log=Logger.getLogger(AfterLogger.class);
@After("execution(* cn.bdqn.service.UserService.*(..))")
public void afterLogger(JoinPoint jp){
log.error(jp.getSignature().getName()+"方法结束执行");
}
}
/**
* 使用@Around注解实现环绕增强
*/
@Aspect
public class AroundLogger {
private static final Logger log=Logger.getLogger(AfterLogger.class);
@Around("execution(* cn.bdqn.service.UserService.*(..))")
public Object aroundLogger(ProceedingJoinPoint jp)throws Throwable{
log.info("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法入参"+Arrays.toString(jp.getArgs()));
try {
Object result=jp.proceed(); //执行目标方法并获得其返回值
log.info("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法返回值"+result);
return result;
} catch (Exception e) {
log.error(jp.getSignature().getName()+"方法发生异常"+e);
throw e;
}finally
{
log.info(jp.getSignature().getName()+"方法结束执行");
}
}
}
4、Spring的切面配置小结
如果项目采用JDK5.0以上版本,可以考虑使用 @AspectJ 注解方式,减少配置的工作量;如果不愿意使用注解或项目采用的JDK版本较低而无法使用注解,则可以选择使用
配合普通JavaBean的形式。