一、使用注解配置Spring
一、注解准备
1、引入新的名称空间,并导入aop包,在xml中配置注解
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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"> <!-- bean definitions here --> <!-- 指定扫描domain包下的所有类中的注解。 注意:扫描包时,会扫描指定包下的所有子孙包 --> <context:component-scan base-package="domain"></context:component-scan> </beans>
2、常用注解说明
将对象交给spring容器
@Component("name")
相当于<bean name="name" class="class"></bean>
@Servlce service层
@Controller web层
@Repository dao层
以上3个与@Component效果相同,开发中经常使用这三个代表对象属于开发中的哪一层
指定对象作用范围
@Scpoe("singleton") @Scpoe("prototype")
是单例还是多例,默认单例,与xml配置中Scope属性一致
值类型注入
@Value(value="张三") 等于@Value("张三")
当注入属性是value时,可以不写value="张三",只写"张三"
值类型注入可以在成员变量上添加注解,也可以在set方法上添加
引用类型注入
方式一、
@Autowired //自动装配
@Qualifier("user") //告诉spring容器自动装配哪个名称的对象
方式二、
@Resource(name="user") //手动注入,指定哪个名称的对象
初始化方法与销毁方法注解
@PostConstract //在对象被创建后调用,init-method
@PreDestroy //在销毁之前调用,destroy-method
代码案例
//@Component("user") //@Service("user")//service层 //@Controller("user")//web层 @Repository("user")//dao层 //@Scope("prototype")//指定对象的作用范围 @Scope("singleton") public class User { public User() { System.out.println("User构造方法执行了"); } @Value("张三")//值类型注入 private String name; @Value("20") private Integer age; //引用类型注入方式一、 //@Autowired//自动装配 //@Qualifier("car")//告诉spring容器自动装配哪个名称的对象 //引用类型注入,方式二 @Resource(name="car")//手动注入,指定注入哪个名称的对象 private Car car; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "User [name=" + name + ", age=" + age + ", car=" + car + "]"; } @PostConstruct//在对象被创建后调用,init-method public void init() { System.out.println("我是初始化方法"); } @PreDestroy//在销毁之前调用 destory-method public void destory() { System.out.println("我是销毁方法"); } }
二、spring整合junit进行测试
导入spring-test包
//Spring整合junit进行测试 //需要导入spring-test包 @RunWith(SpringJUnit4ClassRunner.class)//帮我们创建容器 @ContextConfiguration("classpath:applicationContext.xml")//指定创建容器时使用哪一个配置文件 public class SpringTest1 { //将名为user的对象注入到变量u中 @Resource(name="user") private User u; @Test public void fuc1() { System.out.println(u); } }
二、Spring AOP
1、实现原理
动态代理(优先):被代理对象必须要实现接口,才能产生代理对象。如果没有接口将不能使用动态代理技术
cglib代理:第三方代理,cglib代理可以对任何类生成代理,代理原理是对目标对象进行继承代理。如果目标对象
被final修饰,那么该类无法被cglib代理
2、AOP常用名词
JoinPoint(连接点):目标对象中,所有可以增强的方法
PointCut(切入点):目标对象中准备增强或已经增强的方法
Advice(通知/增强):增强的代码
Target(目标对象):被代理对象
Weaving(织入):将通知应用到切入点的过程
Proxy(代理):将通知织入到目标对象后,形成代理对象
aspect(切面):切入点+通知
3、开发步骤
1、导入aop约束,导包
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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 definitions here -->
需要导入的包为:spring基础包
beans context core express
其他包:
test web commons.logging apache.log4j
aop包:
aop aspects aopalliance aspectj.weaver
2、编写目标对象和通知对象
注意点:在通知对象中的环绕通知
需要传入参数:
ProceedingJoinPoint 类型
ProceedingJonPoint对象执行proceed()方法并将方法的返回对象返回
package AopDemo1; //目标对象 public class UserTarget { public void add() { System.out.println("添加用戶"); } public void update() { int a=1/0; System.out.println("修改用戶"); } public void delete() { System.out.println("刪除用戶"); } public void query() { System.out.println("查詢用戶"); } }
package AopDemo1; import org.aspectj.lang.ProceedingJoinPoint; //通知对象 public class MyAdvice { /** * 前置通知:目标方法运行之前调用 * 后置通知(如果出现异常不会调用) * :在目标方法运行之后调用 * 环绕通知:在目标方法之前和之后都调用 * 异常拦截通知:如果出现异常,就会调用 * 后置通知(无论是否出现异常,都会调用) * :在目标方法运行之后调用 * */ //前置通知 public void before() { System.out.println("这是前置通知"); } //后置通知 public void afterReturning() { System.out.println("这是后置通知(出现异常则不会调用)"); } //环绕通知 //需要手动执行方法并返回结果 public Object around(ProceedingJoinPoint pdj) throws Throwable { System.out.println("环绕通知之前。。。!"); Object proceed = pdj.proceed(); System.out.println("环绕通知之后。。。!"); return proceed; } //异常拦截通知 public void afterException() { System.out.println("出现异常,请注意!"); } //后置通知 public void after() { System.out.println("这是后置通知(即使发生异常也会执行)"); } }
3、将目标对象和通知对象交给Spring容器管理
<!-- 1、配置目标对象 --> <bean name="userTar" class="AopDemo1.UserTarget"></bean> <!-- 2、配置通知对象 --> <bean name="myAdvice" class="AopDemo1.MyAdvice"></bean>
4、配置 AOP 切入点
注意点:配置完成切入点表达式后在<aop:pointcut>中
expression属性:execution(表达式)
<!-- 3、配置切入点 --> <aop:config> <!-- 演化过程: public void AopDemo1.UserTarget.add() void AopDemo1.UserTarget.add() * AopDemo1.UserTarget.add() 不管返回类型是什么 * AopDemo1.UserTarget.*() 不管类中的方法是什么 * AopDemo1.UserTarget.*(..) 不管方法的参数是什么 * AopDemo1.*Target.*(..) 类名以Target结尾的所有类的所有方法 --> <!-- 配置要切入的对象,就是切入点 --> <aop:pointcut expression="execution(* AopDemo1.*Target.*(..))" id="cut"/> <!-- 通知对象为myAdvice --> <aop:aspect ref="myAdvice"> <!-- 指定myAdvice中的before方法作为前置通知,织入到切入点中 --> <aop:before method="before" pointcut-ref="cut"/> <!-- 指定myAdvice中的afterReturning方法作为后置通知(发生异常不执行),织入到切入点中 --> <aop:after-returning method="afterReturning" pointcut-ref="cut"/> <!-- 指定myAdvice中的around方法作为环绕通知,织入到切入点中 --> <aop:around method="around" pointcut-ref="cut"/> <!-- 指定myAdvice中的around方法作为异常拦截通知,织入到切入点中 --> <aop:after-throwing method="afterException" pointcut-ref="cut"/> <aop:after method="after" pointcut-ref="cut"/> </aop:aspect> </aop:config>
5、测试
package AopDemo1; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:AopDemo1/applicationContext.xml") public class AopTest { @Resource(name="userTar") private UserTarget user; @Test public void func1() { user.add(); //user.update(); } }
三、使用注解配置AOP
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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 definitions here --> <!-- 开启依赖注入扫描注解 --> <context:component-scan base-package="AopDemo2"></context:component-scan> <!-- 开启AOP 注解完成织入 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
package AopDemo2; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Component("myAdvice") @Aspect //标识该类为通知类 public class MyAdvice { @Pointcut("execution(* AopDemo2.*Target.*(..))") public void cut() {} //前置通知 @Before("MyAdvice.cut()") public void before() { System.out.println("这是前置通知"); } //后置通知 @AfterReturning("MyAdvice.cut()") public void afterReturning() { System.out.println("这是后置通知(出现异常则不会调用)"); } //环绕通知 //需要手动执行方法并返回结果 @Around("MyAdvice.cut()") public Object around(ProceedingJoinPoint pdj) throws Throwable { System.out.println("环绕通知之前。。。!"); Object proceed = pdj.proceed(); System.out.println("环绕通知之后。。。!"); return proceed; } //异常拦截通知 @AfterThrowing("MyAdvice.cut()") public void afterException() { System.out.println("出现异常,请注意!"); } //后置通知 @After("MyAdvice.cut()") public void after() { System.out.println("这是后置通知(即使发生异常也会执行)"); } }
package AopDemo2; import org.springframework.stereotype.Component; //目标对象 @Component("userTar") public class UserTarget { public void add() { System.out.println("添加用戶"); } public void update() { int a=1/0; System.out.println("修改用戶"); } public void delete() { System.out.println("刪除用戶"); } public void query() { System.out.println("查詢用戶"); } }
package AopDemo2; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:AopDemo2/applicationContext.xml") public class AopTest1 { @Resource(name="userTar") private UserTarget user; @Test public void test() { user.add(); } }