使用注解配置springjava
1.导入 spring-aop-5.0.6.RELEASE.jar包web
2.为主配置文件引入新的命名空间 xmlns:context="http://www.springframework.org/schema/context"spring
<?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-4.0.xsd"> <!--指定扫描com.david.bean下的全部包全部类中的注解 --> <context:component-scan base-package="com.david.bean"></context:component-scan> </beans>
3.在类中使用注解express
@Component("user") //至关于<bean name="user" class="com.david.bean.User" /> public class User { private String name; private Integer age; private Car car; ... }
注解后来又出现了三种,能够体现层级关系编程
@Component("user") @Service("user") //service层 @Controller("user") //web层 @Repository("user") //dao层
指定做用范围框架
@Component("user") //至关于<bean name="user" class="com.david.bean.User" /> @Scope(scopeName = "prototype") //至关于<bean name="user" class="com.david.bean.User" scope="prototype"></bean>
值类型注入oop
public class User { @Value("david") //字段注入 破坏了封装性 private String name; private Integer age; private Car car; @Value("18") //set方法注入 推荐使用 public void setAge(int age) { this.age = age; } ... }
引用类型(对象)注入测试
@Component("car") public class Car { @Value("奥拓") private String name; @Value("red") private String color; ... }
@Component("user") public class User { @Autowired //自动装配 对象注入 private Car car; ... }
@autowired 自动装配的方式 若是匹配到多个类型一致的对象,没法选择具体注入哪个对 如:this
<bean name="car2" class="com.david.bean.Car"> <property name="name" value="奥迪"></property> <property name="color" value="black"></property> </bean>
此时须要使用@Qualifier("car2")注解告诉容器具体注入哪一个对象 和@autowired一块儿使用spa
@Autowired @Qualifier("car2") private Car car;
上面这种要使用两个注解,还有一个注解@Resource 能够手动指定注入哪一个对象
@Resource(name="car2") //手动指定 private Car car;
初始化和销毁
public class User { ... @PostConstruct //至关于init-method 对象建立后调用 public void init(){ System.out.println("init"); } @PreDestroy //销毁前调用 至关于destory-method public void destory(){ System.out.println("destory"); } ... }
aop:面向切面编程,是对oop面向对象编程的补充和完善。
spring中的aop
spring可以为容器中管理的对象生成动态代理对象。
spring实现aop的原理
1.动态代理(优先使用)
被代理对象必需要实现接口,才能产生代理对象,若是没有接口将不能使用动态代理技术
2.cglib代理(没有接口时)
第三方代理技术,能够对任何类生成代理对象。代理的原理是对目标对象进行继承代理
spring AOP 名词解释:
1.Joinpoint链接点:目标对象中,全部能够加强的方法。(能够加强的方法)如:UserServiceImpl implements UserService 中实现的方法 save() delete()
2.Pointcut切入点:目标对象中,已经加强的方法。(已加强的方法)如:已经过代理加强的save() 或delete() 能够单独指定某些加强或不加强。
3.Advice通知/加强:须要加强的代码。(代理对象调用目标方法先后执行的代码)如://前加强 method.invoke(us,arg) //后加强。
4.Target目标对象:被代理对象。如UserServiceImpl。
5.Weaving织入:将通知织入(应用到)切入点的过程。
6.Proxy代理:将通知织入道目标对象以后,造成代理对象。
因此进行AOP编程的关键就是定义切入点和定义加强处理,一旦定义了合适的切入点和加强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=加强处理+被代理对象的方法。
基于spring的aop实现
1.导包 aopalliance.jar aspectjweaver.jar spring aop须要这两个包的支持 下载地址:
http://www.java2s.com/Code/Jar/a/Downloadaopalliancejar.htm
http://www.java2s.com/Code/Jar/a/Downloadaspectjweaverjar.htm
2.准备目标对象
先定义一个接口
public interface IHelloWorld { void printHelloWorld(); void doPrint(); }
在定义两个接口实现类
public class HelloWorldImpl1 implements IHelloWorld { public void printHelloWorld() { System.out.println("Enter HelloWorldImpl1.printHelloWorld()"); } public void doPrint() { System.out.println("Enter HelloWorldImpl1.doPrint()"); return ; } } public class HelloWorldImpl2 implements IHelloWorld{ public void printHelloWorld() { System.out.println("Enter HelloWorldImpl2.printHelloWorld()"); } public void doPrint() { System.out.println("Enter HelloWorldImpl2.doPrint()"); return ; } }
3.准备通知
package com.david.bean; import org.aspectj.lang.ProceedingJoinPoint; public class MyAdvice { //前置通知-目标方法调用以前调用 public void before() { System.out.println("前置通知"); } //后置通知-目标方法以后调用,若是异常不会调用 public void afterRuning() { System.out.println("后置通知,出现异常不会调用"); } //环绕通知-在目标方法以前和以后都调用 public void around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕前通知"); Object proceed = pjp.proceed();//调用目标方法 System.out.println("环绕后通知"); } //异常通知-若是出现异常就会被调用 public void afterException(){ System.out.println("出现异常"); } //后置通知-目标方法以后调用,不管异常与否都会调用 public void after() { System.out.println("后置通知,不管异常与否都会调用"); } }
4.配置进行织入,将通知织入目标对象中
新建一个aop.xml
<?xml version="1.0" encoding="UTF-8"?> <!--导入aop命名空间 --> <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:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <!--配置目标对象 --> <bean id="helloWorldImpl1" class="com.david.bean.HelloWorldImpl1" /> <bean id="helloWorldImpl2" class="com.david.bean.HelloWorldImpl2" /> <!--配置通知对象 --> <bean id="myAdvice" class="com.david.bean.MyAdvice" /> <!--配置将通知织入目标对象 --> <aop:config> <!--配置切入点:全部方法都加强 --> <aop:pointcut id="allMethod" expression="execution(* com.david.bean.IHelloWorld.*(..))"></aop:pointcut> <aop:aspect id="advice" ref="myAdvice"> <!--通知方法 --> <aop:before method="before" pointcut-ref="allMethod" /> <aop:after-returning method="afterRuning" pointcut-ref="allMethod"></aop:after-returning> <aop:around method="around" pointcut-ref="allMethod"></aop:around> <aop:after method="after" pointcut-ref="allMethod" /> </aop:aspect> </aop:config> </beans>
5.编写测试类
public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("aop.xml"); IHelloWorld hw1 = (IHelloWorld)ac.getBean("helloWorldImpl1"); IHelloWorld hw2 = (IHelloWorld)ac.getBean("helloWorldImpl2"); hw1.printHelloWorld(); System.out.println(); hw1.doPrint(); System.out.println(); hw2.printHelloWorld(); System.out.println(); hw2.doPrint(); }
使用spring aop开发 就不须要咱们手写动态代理代码了,还封装了cglib代理。能够对任何类进行代理加强。
spring的aop注解配置
<?xml version="1.0" encoding="UTF-8"?> <!--导入aop命名空间 --> <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:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <!--配置目标对象 --> <bean id="helloWorldImpl1" class="com.david.bean.HelloWorldImpl1" /> <bean id="helloWorldImpl2" class="com.david.bean.HelloWorldImpl2" /> <!--配置通知对象 --> <bean id="myAdvice" class="com.david.bean.MyAdvice" /> <!--开启使用注解织入目标对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
通知类 使用注解设置
@Aspect //表示该类是一个通知类 public class MyAdvice { @Before("execution(* com.david.bean.IHelloWorld.*(..))") //是一个前置通知并指定切入点 public void before() { System.out.println("前置通知"); } @After("execution(* com.david.bean.IHelloWorld.*(..))") public void after() { System.out.println("后置通知,不管异常与否都会调用"); } @AfterReturning("execution(* com.david.bean.IHelloWorld.*(..))") public void afterRuning() { System.out.println("后置通知,出现异常不会调用"); } @Around("execution(* com.david.bean.IHelloWorld.*(..))") public void around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕前通知"); Object proceed = pjp.proceed();//调用目标方法 System.out.println("环绕后通知"); } }
再次运行 效果同样的。 抽取切入点
package com.david.bean; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; @Aspect //表示该类是一个通知类 public class MyAdvice { //定义一个切入点规则 @Pointcut("execution(* com.david.bean.IHelloWorld.*(..))") public void pc(){ } @Before("MyAdvice.pc()") public void before() { System.out.println("前置通知"); } @After("MyAdvice.pc()") public void after() { System.out.println("后置通知,不管异常与否都会调用"); } @AfterReturning("MyAdvice.pc()") public void afterRuning() { System.out.println("后置通知,出现异常不会调用"); } @Around("MyAdvice.pc()") public void around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕前通知"); Object proceed = pjp.proceed();//调用目标方法 System.out.println("环绕后通知"); } }