一.AOP(Aspect Oriented Programing)面向切面编程
AOP的终极目标:让我们可以专心做事
下面通过一个例子来介绍AOP的具体使用
案例的要求:使用AOP实现日志记录系统 , 核心模块 和 增强 单独 开发 ,运行时再组装
首先定义接口和方法
接口和实现类中的代码,我放在一起了,应该比较简单
package demo04.dao;/**
* Created by mycom on 2018/3/5.*/
public interfaceIHelloDao {public voiddoSome();
}
package demo04.dao;
/**
* Created by mycom on 2018/3/5.
*/
public class HelloDaoImpl implements IHelloDao {
public void doSome() {
System.out.println("已经成功加入到DB中了");
}
}
package demo04.service;
/**
* Created by mycom on 2018/3/5.
*/
public interface IHelloService {
public void doSome();
}
package demo04.service;
import demo04.dao.IHelloDao;
/**
* Created by mycom on 2018/3/5.
*/
public class HelloServiceImpl implements IHelloService {
//创建一个Dao的对象
IHelloDao dao;
public IHelloDao getDao() {
return dao;
}
public void setDao(IHelloDao dao) {
this.dao = dao;
}
public void doSome() {
dao.doSome();
}
}
同样在resources下面也要有一个xml文件----applicationContext.xml
这里需要注意一下 class的值只能是实现类的包
然后编写测试类进行测试
@Testpublic voidt1(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContextAop.xml");//这里的返回值只能是接口
IHelloService service =(IHelloService) context.getBean("service");
service.doSome();
}
运行的结果
现在我们要在这句话出现之前,先记录一下日志,出现之后,再出现一句话
首先要创建一个新的包AOP包,并且在包下面写两个类
LoggerAfter是后置增强
LoggerBefore是前置增强
这两个类中的代码如下
package demo04.aop;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;/**
* Created by mycom on 2018/3/5.*/
public classLoggerAfter implements AfterReturningAdvice {public voidafterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("=======after");
}
}
package demo04.aop;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;/**
* Created by mycom on 2018/3/5.*/
public classLoggerBefore implements MethodBeforeAdvice {public voidbefore(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("日志记录");
}
}
在xml中配置,在配置xml是要给AOP添加一个约束
测试类
import demo04.service.HelloServiceImpl;
import demo04.service.IHelloService;
import demo05.MyCollection;
import demo05.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/**
* Created by mycom on 2018/3/3.*/
public classTest20180305 {
@Testpublic voidt1(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContextAop.xml");//这里的返回值只能是接口
IHelloService service =(IHelloService) context.getBean("service");
service.doSome();}
}
在这里和要介绍两个单词的意思
advice :通知
advisor:顾问
顾问可以包装通知
execution(【modifiers-pattern?】 访问修饰符
ret-type-pattern 返回值类型
【declaring-type-pattern?】 全限定性类名
name-pattern(param-pattern) 方法名(参数名) 包名.类型名.方法名
【throws-pattern?】) 抛出异常类型
public void doLog(String log){
}
方法签名
切入点表达式要匹配的对象就是目标方法的方法名。所以,execution表达式中明显就是方法的签名。
注意:表达式中加[]的部分表示可省略部分,各部分间用空格分开。在其中可以使用以下符号:
符号 意义
* 0至多个任意字符
.. 用在方法参数中,表示任意多个参数
用在包名后,表示当前包及其子包路径
+ 用在类名后,表示当前类及其子类
用在接口后,表示当前接口及其实现类
案例:
execution(public * *(..)) 指定切入点为:任意公共方法
execution(* set*(..)) 指定切入点为:任何一个以"set"开始的方法
二.给属性注入值(四种)
1.setter方法注入(就是在bean节点下有property节点给里面的属性值赋值
2.构造注入
3.p命名空间注入(使用前要先要在Spring配置文件中引入p命名空间xmlns:p="http://www.springframework.org/schema/p")
这里的两种我写在一起了
首先写一个学生类,车类,MyCollection
package demo05;/**
* Created by mycom on 2018/3/5.*/
public classStudent {privateString name;privateInteger age;privateCar car;publicStudent() {
}publicStudent(String name, Integer age) {this.name =name;this.age =age;
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}publicInteger getAge() {returnage;
}public voidsetAge(Integer age) {this.age =age;
}publicCar getCar() {returncar;
}public voidsetCar(Car car) {this.car =car;
}
}
package demo05;/**
* Created by mycom on 2018/3/5.*/
public classCar {privateString color;privateString brand;publicString getBrand() {returnbrand;
}public voidsetBrand(String brand) {this.brand =brand;
}publicString getColor() {returncolor;
}public voidsetColor(String color) {this.color =color;
}
}
在xml中的配置
最后编写测试类
以p命名空间注入为例进行测试
import demo04.service.HelloServiceImpl;
import demo04.service.IHelloService;
import demo05.MyCollection;
import demo05.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/**
* Created by mycom on 2018/3/3.*/
public classTest20180305 {
@Testpublic voidt1(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContextCon.xml");
Student service2 =(Student) context.getBean("stu");
System.out.println(service2.getName());
} }
4.集合注入
再写一个MyCollection类
package demo05;
import java.util.*;/**
* Created by mycom on 2018/3/5.*/
public classMyCollection {privateString[] array;private Listlist;private Set set;private Mapmap;privateProperties properties;publicMyCollection() {
System.out.println("创建对象===========");
}public MyCollection(String[] array, List list, Set set, Mapmap, Properties properties) {this.array =array;this.list =list;this.set = set;this.map =map;this.properties =properties;
}@Override
public String toString() {
return "MyCollection{" +
"array=" + Arrays.toString(array) +
", list=" + list +
", set=" + set +
", map=" + map +
", properties=" + properties +
'}';
}
publicString[] getArray() {returnarray;
}public voidsetArray(String[] array) {this.array =array;
}public ListgetList() {returnlist;
}public void setList(Listlist) {this.list =list;
}public SetgetSet() {return set;
}public void setSet(Set set) {this.set = set;
}public MapgetMap() {returnmap;
}public void setMap(Mapmap) {this.map =map;
}publicProperties getProperties() {returnproperties;
}public voidsetProperties(Properties properties) {this.properties =properties;
}
}
小明
小兰
list1
list2
set1
set2
01
02
001
002
import demo04.service.HelloServiceImpl;
import demo04.service.IHelloService;
import demo05.MyCollection;
import demo05.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/**
* Created by mycom on 2018/3/3.*/
public classTest20180305 {
@Testpublic voidt1(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContextCon.xml");//返回的类型只能是接口
MyCollection service =(MyCollection) context.getBean("collection");
System.out.println(service);}
}
三.Spring中bean是单例的问题
单例:一个类在内存中只能有一个对象。
单利满足的三个条件:
1.构造私有
2.是有的静态变量,变量的类型就是当前类的类型
3.提供一个静态方法
在xml中配置实现单例还是多例的属性是scope
他的值有两个singleton 单例
prototype 多例
在上面的集合注入的例子中进行改动,并且如果MyCollection中有toString方法,也要注释掉,可以更直观的看到,如下
然后我们来编写测试方法进行测试
import demo04.service.HelloServiceImpl;
import demo04.service.IHelloService;
import demo05.MyCollection;
import demo05.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/**
* Created by mycom on 2018/3/3.*/
public classTest20180305 {
@Testpublic voidt1(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContextCon.xml");
MyCollection service=(MyCollection) context.getBean("collection");
System.out.println(service);
MyCollection service2=(MyCollection) context.getBean("collection");
System.out.println(service2);
}
}
运行结果
从运行结果来看,两次创建的对象的指针不同,创建的是两个对象,这是多例
线面再来看单例,将scope的属性值改为singleton
此时的运行结果如下
他只创建了依次对象,实现了单利