1.使用注解配置spring
1.1 引入新的命名空间(约束)
如果是使用eclipse的同学,那么肯定是很熟悉这个了。使用idea的话,就不需要自己引入了,idea已经将约束添加好了
1.2 在spring的配置文件中开启注解
<!--指定扫面 bean 包下的所有类 的注解-->
<context:component-scan base-package="bean"/>
1.3 在类中使用注解
// 相当于在xml配置文件中写<bean name="user" class="bean.user" />
@Component("user") // 早期使用,当初只有component,后续细化出了下面三个,用于不同的层,方便阅读
@Service("user") // service层
@Controller("user") // web层
@Repository("user") // dao层
1.4 测试
@Test
public void testFunc01() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user);
}
2. 使用注解
2.1 使用Scpoe
@Repository("user") // dao层
@Scope("prototype")
public class User {
private String name;
private Integer age;
private Dog dog;
2.2 基本数据类型赋值
- 在属性上赋值
通过反射的field赋值,破坏封装性,但是可读性好
public class User {
@Value("tom")
private String name;
@Value("18")
private Integer age;
- 在set方法上赋值
在set方法赋值,推荐使用,但是可读性不太好
@Value("tom")
public void setName(String name) {
this.name = name;
}
@Value("18")
public Integer getAge() {
return age;
}
2.3 引用类型赋值
先给dog类赋值
@Component("dog")
public class Dog {
@Value("柯基")
private String name;
@Value("3")
private Integer age;
- 手动注入,指定注入哪个名称的对象
@Resource(name = "dog")
private Dog dog;
- @Autowired 自动装配
问题:如果发现多个类型一致的对象,将无法选择具体注入哪一个对象
如果需要指定注入某一个对象,需要添加辅助注解
在User 中只需要添加注解
@Autowired
@Qualifier("dog2")
private Dog dog;
2.4 创建和销毁注解
@PostConstruct // 在对象创建后调用,相当于init-method
public void init() {
System.out.println("初始化方法调用");
}
@PreDestroy // 在对象销毁之前调用,相当于destroy-method
public void destroy() {
System.out.println("销毁方法调用");
}
3. spring junit整合测试
这样就不需要在每个测试方法中都重复书写获取对象的代码
// 帮我们创建容器
@RunWith(SpringJUnit4ClassRunner.class)
// 指定创建容器使用哪一个配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class Test02 {
@Resource(name = "user")
private User user;
@Test
public void testFunc01() {
System.out.println(user);
}
}
4. spring aop
4.1 aop 名词
Joinpoint(连接点):目标对象中,所有可以增强的方法。(可以增强的方法)
Pointcut(切入点):目标对象中,已经被增强的方法。(已经增强的方法)
Advice(通知/增强):增强的代码。(例如:打开事务,关闭事务)
Target(目标对象):被代理对象
Weaving(织入):将通知应用到连接点的过程
6.Proxy(代理):将通知织入到目标对象之后,形成代理对象
7.Aspect(切面):切入点+通知
4.2 配置将通知织入目标对象
- 准备一个通知类
/// 通知类
public class MyAdvice {
public MyAdvice() {
}
// 前置通知 -》目标方法调用之前调用
public void before() { System.out.println("这是前置通知"); }
// 后置通知(如果出现异常不会调用)-》在目标方法调用之后调用
public void afterReturning() { System.out.println("这是后置通知"); }
// 环绕通知 -》在目标方法调用之前和之后都调用
public Object around(ProceedingJoinPoint pjp) throws Throwable {
// 调用目标方法
System.out.println("这是环绕通知前部分");
Object proceed = pjp.proceed();
System.out.println("这是环绕通知后部分");
return proceed;
}
// 异常拦截通知 -》如果出现异常会调用
public void afterException() {
System.out.println("这是异常拦截通知");
}
// 后置通知(如果出现异常仍会调用)-》在目标方法调用之后调用
public void after() {
System.out.println("这是后置通知-出现异常仍会调用");
}
}
- 配置通知对象和通知方法
<!--配置目标对象-->
<bean name="userService" class="service.UserServiceImpl"></bean>
<!--配置通知对象-->
<bean name="myAdvice" class="springAop.MyAdvice"></bean>
<!--配置将通知织入目标对象-->
<!--
public void service.UserServiceImpl.save()
void service.UserServiceImpl.save()
* service.UserServiceImpl.*()
* service.*ServiceImpl.*(..)
-->
<aop:config>
<aop:pointcut expression="execution(* service.*ServiceImpl.*(..))" id="pc"/>
<aop:aspect ref="myAdvice" >
<!-- 指定名为before方法作为前置通知 -->
<aop:before method="before" pointcut-ref="pc" />
<!-- 后置 -->
<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>
3.进行测试
// 帮我们创建容器
@RunWith(SpringJUnit4ClassRunner.class)
// 指定创建容器使用哪一个配置文件
@ContextConfiguration("classpath:springAop/applicationContext.xml")
public class Test03 {
@Resource(name = "userService")
private UserService us;
@Test
public void testFunc01() {
us.save();
}
}
-
结果输出
4.3 使用注解配置 将通知织入目标对象
1.在配置文件中开启自动代理
<aop:aspectj-autoproxy/>
2.在通知类中进行配置
/// 通知类
@Aspect
public class MyAdvice {
@Pointcut("execution(* service.UserServiceImpl.*(..))")
public void pc() {}
// 前置通知 -》目标方法调用之前调用
@Before("MyAdvice.pc()")
public void before() { System.out.println("这是前置通知"); }
// 后置通知(如果出现异常不会调用)-》在目标方法调用之后调用
@AfterReturning("MyAdvice.pc()")
public void afterReturning() { System.out.println("这是后置通知 (如果出现异常不会调用)"); }
// 环绕通知 -》在目标方法调用之前和之后都调用
@Around("MyAdvice.pc()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
// 调用目标方法
System.out.println("这是环绕通知前部分");
Object proceed = pjp.proceed();
System.out.println("这是环绕通知后部分");
return proceed;
}
// 异常拦截通知 -》如果出现异常会调用
@AfterThrowing("MyAdvice.pc()")
public void afterException() {
System.out.println("这是异常拦截通知");
}
// 后置通知(如果出现异常仍会调用)-》在目标方法调用之后调用
@After("MyAdvice.pc()")
public void after() {
System.out.println("这是后置通知(如果出现异常仍会调用)");
}
}