使用注解配置Spring、Spring-Aop
使用注解配置Spring
导包
使用注解配置Spring需要导入 spring-aop-4.2.4.RELEASE.jar 包
导入约束
在主配置文件中导入新的命名空间,也就是导入约束
xmlns:context="http://www.springframework.org/schema/context"
开启使用注解代替配置文件
<context:component-scan base-package=""></context:component-scan>
在主配置文件applicationContext.xml中,全部代码如下
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd "> 6 7 <!-- 8 指定扫描com.jinxin.bean包下所有类的注解 9 注意:扫描包时会扫描该包下所有的子孙包 10 --> 11 <context:component-scan base-package="com.jinxin.bean"></context:component-scan> 12 13 </beans>
开始使用注解
将对象注册到容器
在要交给容器管理的类上面使用 @Component("name") 注解,就可以代替<bean>标签
考虑到区分不同的代码层也可以分别使用如下三个标签来注册
@Service("name") // service层
@Controller("name") // web层
@Repository("name") // Dao层
效果同@Component("name")一致
例:
将UserInfo交给容器管理
1 import org.springframework.stereotype.Component; 2 3 @Component("userinfo") 4 public class UserInfo { 5 private String name; 6 private Integer age; 7 8 public String getName() { 9 return name; 10 } 11 public void setName(String name) { 12 this.name = name; 13 } 14 public Integer getAge() { 15 return age; 16 } 17 public void setAge(Integer age) { 18 this.age = age; 19 } 20 }
测试
1 import org.junit.Test; 2 import org.springframework.context.support.ClassPathXmlApplicationContext; 3 4 public class NewTest { 5 @Test 6 public void test() { 7 ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 8 UserInfo ui = (UserInfo) ac.getBean("userinfo"); 9 System.out.println(ui); 10 } 11 }
修改对象的作用范围
使用 @Scope(ScopeName="property") 代替<bean>标签里面的scope属性为对象设置作用范围
例:
将UserInfo修改为多例
1 import org.springframework.context.annotation.Scope; 2 import org.springframework.stereotype.Component; 3 4 @Component("userinfo") 5 @Scope(scopeName="prototype") 6 public class UserInfo { 7 private String name; 8 private Integer age; 9 10 public String getName() { 11 return name; 12 } 13 public void setName(String name) { 14 this.name = name; 15 } 16 public Integer getAge() { 17 return age; 18 } 19 public void setAge(Integer age) { 20 this.age = age; 21 } 22 23 }
测试
1 import org.junit.Test; 2 import org.springframework.context.support.ClassPathXmlApplicationContext; 3 4 public class NewTest { 5 @Test 6 public void test() { 7 ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 8 UserInfo ui = (UserInfo) ac.getBean("userinfo"); 9 UserInfo ui1 = (UserInfo) ac.getBean("userinfo"); 10 System.out.println(ui == ui1); 11 } 12 }
值类型注入
值类型注入可以使用属性注入跟set方法注入(推荐)两种,其中set方法注入更加推荐
例:
1 import org.springframework.beans.factory.annotation.Value; 2 import org.springframework.context.annotation.Scope; 3 import org.springframework.stereotype.Component; 4 5 @Component("userinfo") 6 @Scope(scopeName="prototype") 7 public class UserInfo { 8 @Value("timo") // 属性注入 9 private String name; 10 private Integer age; 11 12 public String getName() { 13 return name; 14 } 15 @Value("taylor") // set方法注入(推荐) 16 public void setName(String name) { 17 this.name = name; 18 } 19 public Integer getAge() { 20 return age; 21 } 22 public void setAge(Integer age) { 23 this.age = age; 24 } 25 26 }
引用类型注入
引用类型注入分为两种,自动装配(@Autowired)跟手动装配(@Resource(name="girlfriend"))
例:
准备一个GirlFriend类作为UserInfo的引用类型属性
1 import org.springframework.beans.factory.annotation.Value; 2 import org.springframework.stereotype.Repository; 3 4 @Repository("girlfriend") 5 public class GirlFriend { 6 private String name; 7 private Integer age; 8 9 public String getName() { 10 return name; 11 } 12 @Value("Scarlet") 13 public void setName(String name) { 14 this.name = name; 15 } 16 public Integer getAge() { 17 return age; 18 } 19 @Value("18") 20 public void setAge(Integer age) { 21 this.age = age; 22 } 23 }
在UserInfo中为其注入值
1 import javax.annotation.Resource; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.beans.factory.annotation.Value; 5 import org.springframework.context.annotation.Scope; 6 import org.springframework.stereotype.Component; 7 8 @Component("userinfo") 9 @Scope(scopeName="prototype") 10 public class UserInfo { 11 private String name; 12 private Integer age; 13 @Autowired // 自动装配 14 @Resource(name="girlfriend") // 手动装配(指定girlfriend为装配对象) 15 private GirlFriend girlFriend; 16 17 public GirlFriend getGirlFriend() { 18 return girlFriend; 19 } 20 21 public void setGirlFriend(GirlFriend girlFriend) { 22 this.girlFriend = girlFriend; 23 } 24 public String getName() { 25 return name; 26 } 27 public void setName(String name) { 28 this.name = name; 29 } 30 public Integer getAge() { 31 return age; 32 } 33 public void setAge(Integer age) { 34 this.age = age; 35 } 36 37 @Override 38 public String toString() { 39 // TODO Auto-generated method stub 40 return girlFriend.getName() + "-->" + girlFriend.getAge(); 41 } 42 }
测试
1 import org.junit.Test; 2 import org.springframework.context.support.ClassPathXmlApplicationContext; 3 4 public class NewTest { 5 @Test 6 public void test() { 7 ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 8 UserInfo ui = (UserInfo) ac.getBean("userinfo"); 9 System.out.println(ui); 10 } 11 }
初始化&销毁方法
使用注解 @PostConstruct 跟 @PreDestory 指定初始化方法跟销毁方法
例:
@PostConstruct
public void start(){
System.out.println("我是初始化方法");
}
@PreDestory
public void destory(){
System.out.println("我是方法");
}
名词学习
- 连接点:目标对象中,所有可以增强的方法
- 切入点:目标对象中,已经增强的方法
- 通知/增强:增强的代码
- 目标对象:被代理的对象
- 织入:将通知应用到切入点的过程
- 代理:将通知织入到目标对象,形成代理对象
- 切面:切入点+通知
Spring-aop
- 前置通知:目标方法运行之前执行
- 后置通知:目标方法之后运行,如果出现异常则不会调用
- 环绕通知:在目标方法运行之前和之后都会调用
- 异常拦截通知:如果出现异常就会调用
- 后置通知:目标方法运行之后调用,无论是否出现异常都会调用
首先准备一个类作为通知类
这个类主要存放的是前置通知后置通知等执行的方法
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAdvice {
// 前置通知
public void before() {
System.out.println("这是前置通知");
}
// 后置通知
public void afterReturning() {
System.out.println("这是后置通知 出现异常不调用");
}
// 环绕通知
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("这是环绕通知之前的部分");
Object proeed = pjp.proceed();
System.out.println("这是环绕通知之后的部分");
return proeed;
}
// 异常拦截通知
public void afterException() {
System.out.println("异常拦截通知");
}
// 后置通知
public void after() {
System.out.println("后置通知 (无论是否出现异常都会调用)");
}
}
准备一个类作为被通知的类
这个类是我们需要执行的类,在执行类中的方法的时候会调用前置通知,后置通知,环绕通知等一系列通知
public class UserService {
public void save() {
System.out.println("保存方法");
}
}
在主配置文件中进行配置
虽然已经有了通知类和被通知类,但是还需要在配置文件中进行配置指定被通知类的前置通知,后置通知等要执行方法
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
<!--
指定扫描com.jinxin.bean包下所有类的注解
注意:扫描包时会扫描该包下所有的子孙包
-->
<context:component-scan base-package="com.jinxin.bean"></context:component-scan>
<!-- 配置目标对象 -->
<bean name="user" class="com.jinxin.bean.UserService"></bean>
<!-- 配置通知对象 -->
<bean name="myAdvice" class="com.jinxin.aop.MyAdvice"></bean>
<aop:config>
<!-- 配置切入点
public void com.jinxin.bean.UserService.save()
void com.jinxin.bean.UserService.save()
* com.jinxin.bean.UserService.*()
* com.jinxin.bean.UserService.*(..)
* com.jinxin.bean.*Service.*(..)
-->
<aop:pointcut expression="execution(* com.jinxin.bean.*Service.*(..))" id="pc"/>
<aop:aspect ref="myAdvice">
<!--指定名为before方法作为前置通知 -->
<aop:before method="before" pointcut-ref="pc" />
<!--指定名为afterReturning方法作为后置通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="pc" />
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pc" />
<!-- 异常拦截通知 -->
<aop:after-throwing method="afterException" pointcut-ref="pc"/>
<!-- 后置通知 -->
<aop:after method="after" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
</beans>
在配置切入点的时候有一个小插曲,原本要配置的形态是这样 public void com.jinxin.bean.UserService.save() ,最后却变成了这样 * com.jinxin.bean.*Service.*(..) ,下面对这些*号进行一一的解释
public void ---> *
将public void用*代替表示了可以通知任意类型的方法
UserService ---> *Service
将UserService用*Service代替,表示可以通知任意xxxService形式的类
save ---> *
将save方法替换成了*表示可以通知该类中所有的方法
() ---> (..)
将()替换成(..)表示可以接受任意参数的方法

浙公网安备 33010602011771号