分两大块 :
1 控制反转 IOC : 控制类的实例化,以及他们的调用关系
2 动态代理 AOP : 主要是事务机制的控制
//控制反转 : IOC(又叫DI)
////四种解析方式 :
//四种方式获取属性 四种获取属性的方式
//四种方式读取属性 四种读取属性的方式
1 DOM : //把所有属性都弄到文档对象中,全部读取 一个报错,全部不读取
2 JDOM : //把所有属性都弄到文档对象中,全部读取 一个报错,全部不读取
3 DOM4J : //把所有属性都弄到文档对象中,全部读取 一个报错,全部不读取
4 SAX : //用IO流,一个一个读取,读取一个,放进去一个 哪里报错,报错处往后就不读取,前面读取
DOM : == Document Object Model : 文档对象模型
SAX : 基于事件和流的方式解析xml
sax,DOM : 这两种已经加入java的核心包,不再需要第三方宝
JDOM : 是DOM的一种增强版本
DOM4J : JDOM的一个子项目
//解析XML文件,解析XML文件的方式都大同小异 :
1 获得根节点
2 遍历根节点里面的子节点
3 获取子节点里面的属性
4 遍历节点里面的内部(子节点)节点
所以XML文件就三层,再多的话,就会被骂
//子节点和属性的区别 :
<user id="2">//属性
<name>图图</name>//子节点
</user>
子节点和属性本质一回事,都是保存数据的,只是根据不同的需求和数据的属性写到了不同的位置
被描述的那个主题对象的内部属性,一般用节点声明
不是主题对象内部属性,一般用属性声明
//子节点的本质,属性的本质,子节点和属性的本质 :
本质 : 都是保存数据的,只是根据不同的需求和数据的属性写到了不同的位置
DOM :
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();//创建工厂对象,用于创建别的对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();//用工厂对象创建对象,用于调用方法,获取xml文件
parse :
//用于获取xml全部内容,返回值是Docement 是上面的DocumentBuilder的对象,调用的方法,
Document document = documentBuilder.parse("XML文件的全路径");// 这就是把整个xml文件全部取出来,转化成Document对象
getChildNodes :
//获得所有文档里面的一级的子节点 返回值是NodeList类型(集合) 是上面的Document对象,调用的方法
NodeList users = document.getChildNodes();//获得所有文档的子节点 , 如 : body , head ...,这里是那些注释和<users> (任意写的标签)
item :
//item(下标); 用NodeList的对象,调用这个方法,返回值是Node类型 获得集合上对应下标的元素
Node user = users.item(i);// item(index)获得子节点 users 获得相应索引上面的元素,就是下标上面的元素
getLength :
//getLength() ; 用NodeList的对象,调用这个方法,返回值是int类型 获得集合的长度
int i = users.getLength();//返回users集合(NodeList集合)的长度
getNodeName :
//getNodeName();//获得标签的名字,用Node对象调用这个方法,返回值是String
String s = user.getNodeName();
getTextContent :
//getTextContent();//获得文本节点,用Node对象调用这个方法,返回值时String
String s = user.getTextContent();
JDomDemo :
SAXBuilder builder = new SAXBuilder();//创建工厂对象
build :
//用于获取xml全部内容,返回值是Docement 是上面的SAXBuilder的对象,调用的方法,
Document document = builder.build("xml全路径");//获取xml文件的全部内容
getRootElement :
//获得根节点,返回值时Element类型 是上面的Document的对象调用的这个方法
Element users = document.getRootElement();//获得根节点
getChildren :
//获得里面的所有指定子节点 , 返回值是List类型,是上面Element的对象调用的这个方法
List userList = users.getChildren("user");//获得里面所有的user子节点
size :
//返回集合里面的元素个数,返回值是int , 是上面List的对象调用的这个方法
int i = userList.size();
get :
get();//根据下标获取指定的元素
Element element = (Element) lists集合.get(下标);//获得单个的子节点里面的子节点里面的属性,强制转型为Element类型来接收
getAttributeValue :
//获得的是内部属性 如 : <user id="2" > 是获得这里面的id
String id = element.getAttributeValue("id"); //获取节点的属性值(是属性,不是子节点),返回值是个字符串
getName :
getName();//获得属性的名字(标签名)
String s = element.getName();//上面获得了节点里面的属性,这个是用那个节点的对象,调用方法,来获得节点的名字
getValue :
getValue();//获得属性的值(标签的值(就是文本节点))
String s = element.getValue();//上面获得了节点里面的属性,这个是用那个节点对象,调用方法,来获得节点的值
Dom4JDemo :
SAXReader saxReader = new SAXReader();//创建工厂
File inputXml = new File("文件全路劲");//把文件全部加载
Document document = saxReader.read(inputXml);//阅读文件
Element users = document.getRootElement();//一级节点(users根节点)
for (Iterator i = users.elementIterator(); i.hasNext();) {//遍历
Element user = (Element) i.next();//二级节点
for (Iterator j = user.elementIterator(); j.hasNext();) {
Element node = (Element) j.next();//三级子节点
System.out.println(node.getName()+":"+node.getText());
}
System.out.println();
}
elementIterator :
//用Element对象调用这个方法elementIterator(),是元素的迭代器方法
Interator j = user.elementIterator();//把每个元素,都给了 j
hasNext :
hasNext();//访问下位还有没有元素,指针在顶端,返回值为boolean true/false
j.hasNext();
next :
next();//获取下位元素
Element node = (Element)j.next();//获取下一位的元素,然后转向为Element
getName :
getName();//获得元素的名字(就是标签名),用Element对象调用
node.getName();//获得标签的名字
getText :
getText();//获得标签/属性的值(文本节点的内容)
node.getText();//用Element对象调用这个方法
SAX :
类必须继承DefaultHandler
startDocument()//开始读取的时候,自动调用的方法
endDocument()//读取结束的时候,自动调用的方法
getLength :
Attributes 类型的对象,调用这个方法
attributes.getLength();//获得属性的长度
getQName :
Attributes 类型的对象,调用这个方法
attributes.getQName(0);//获得属性的名字
getValue :
Attributes 类型的对象,调用这个方法
attributes.getValue(0);//获得属性的值
getBean :
getBean("ID/name");//获得xml中 <bean>标签中的id或者name所对应的类的对象
@Component :
写在类上面,就会实例化当前类
1 @Component 实例化当前类并使用默认名字
2 @Component("userDAO") 实例化当前类,并指定名字
3 @Component(value="userDAO") 实例化当前类并指定名字
@Autowired
//写在,在当前类中,保存别的类的引用的成员变量,对应的set**();方法上
从容器里面找一个和这个参数类型对应的bean注入进来,注意和beans.xml文件结合起来理解
Autowired: 默认是byType的,可能是多个的问题,但是容易出现重复,这个可以解决,但是4.0不写也没问题
@Qualifier用法 就会去对xml中对应的名字,获取对象
@Autowired
public void set***(@Qualifier("xml中对应的名字")形参列表){ }
@Resource(name="userDAO")
//写在,在当前类中,保存别的类的引用的成员变量,对应的set**();方法上
这里引用了一个资源,默认是byName;当名字找不到的时候,就byType,可以指定一个名字
在JSR-250中,当你要用注解的方式声明一个按照名字装配的bean的时候,强烈建议用resource而不是autowire,即使指定@Qualifier 在对应方法形参列表里面(@Qualifier("xml中对应的名字") , 参数)
但是按照byType(按照类名,class属性的时候),用autoWire
//AOP : 动态代理
AOP :
// 产生个代理对象
// 1 要产生对象--->是不是要先用***.class---->ClassLoader,产生***.class
// 要求,被代理对象和代理独享的ClassLoader必须是同一个,要不然互相之间访问不了,**.class
// 带来对象内部还包含了一个代理对象,所以是同一个ClassLoader
// 2 产生被代理对象所实现的接口,代理对象也要实现相同的接口
// 3 产生代理对象以后,要调用代理里面的方法,谁来处理,就是那个handler
// 用什么产生代理对象: Proxy.newProxyInstance
// 这里只是一种机制而已,具体的代理的代理对象和被代理对象,是你自己实现处理的
// 写多少就代理多少
//目标是获得代理的那个对象,被代理类的接口的加载器,就是代理类加载器,因为这个代理类是自动生成的
LogInterceptor li = new LogInterceptor();//代理类,有所有接口的时候,的引用
UserDAO userDAOProxy = (UserDAO) Proxy.newProxyInstance(userDAO.getClass().getClassLoader(),new Class[] { UserDAO.class }, li);//确定接口 三个参数 (加载器 , 被代理类的父接口(实现的接口的Class对象(**.class)) , 代理类的对象 ) 获得的就是指定接口的代理类的对象,是虚拟的
userDAOProxy.save(new User());//确定方法 用那个虚拟的指定了接口的代理类的对象,调用方法.调用什么方法,代理的就是什么方法,这里代理的是save()方法
然后会去调用代理类的invoke()方法,并且把上面的那个userDAOProxy.save(new User()) ,当做参数列表传过去 , 代理类的invoke方法有三个参数 :
1 对象 指定了接口的代理类的对象(虚拟的,不能用)
2 方法名 (这里是save , 但是底层经过处理,把方法名,弄成了method的对象)
3 参数 ( Object[] args 别管传什么对象过去,Object类型的数组,都能接下,并向上转型了吧)
//xml里面设置用强注释
<aop:aspectj-autoproxy />// 这是AOP的自动配置 和IOC/DI的强注释,没有任何关系
@Aspect :
@Aspect : 在类的上面写上这个标签,就说明是使用注解方式 AOP
@PostConstruct :
@PostConstruct 写在init()方法上面 就是执行的时候(实例化当前类的时候),先自动调用此方法
@PreDestroy :
@PreDestroy 写在destory()方法上面,调用执行此方法,创建的那个对象销毁
如果,xml中,scope="singleton"的时候(单例模式) 调用此方法,就会销毁对象
prototype 的时候(要多少对象,就创建多少对象) 调用此方法,也不会销毁对象
@Pointcut :
Spring(IOC),用注解的时候,每个类型的类都有固定的修饰符修饰,
@Controller(Action),@Service(service),@Repository(DAO),@Component(model,能修饰所有类)
这样以后,所有的类都可以纳入spring的控制范畴
pointcut : 实际是指方法调用的时候
advice : 方法调用前后执行代码
@Pointcut : advice+pointcut 针对某一个方法,和另一个方法的交界处,切断,拦截,并由这个地方,链接这两个方法 ,后面那个是指定代理的方法(public *(返回值) 包..*(某个包里面的所有类).方法名(..(参数列表) ) ) 这个注解,写在哪个方法上面,就用这个方法,代替需要代理的方法
写法 , 如 :
@Pointcut("execution(public * com.jaovo.service..* .add(..))") //那么这个方法,就代替add()方法,如果想在add()方法调用前后执行别的东西,就用@Before,@After,@Around
Advice :
@Before(前),@AfterReturning(返回值后),@AfterThrowing(异常后),@After(后),@Around(前后)
方法调用前后执行代码
@Before :
@Before : 执行指定方法之前,就执行的方法
@Before("被代理的方法/代替被代理的方法")//在被代理方法调用执行之前,先执行用@Before修饰的方法
@Before("execution(public void com.jaovo.dao.impl.UserDAOImpl.save(com.jaovo.model.User))")//这是指定了某个方法,公共的,没有返回值的,UserDAOImpl类里面的save()方法,并且这个方法的参数是User类型 , 再某个方法上面写了这个,就是说,这个save()方法执行之前,先执行用@Before修饰的方法
@Before("execution(public * com.jaovo.dao..*.*(..))")//指定了,公共的 任意返回值的,dao包下的任意包,任意类,任意方法,任意形参列表 , 调用这些方法的时候,就会先执行用@Before修饰的方法
@Before("myMethod()")//这个就是当代替被代理方法的这个方法执行前,.先执行用@Before修饰的方法
@After :
@After : 执行指定方法完毕,就执行的方法
@After("被代理的方法/代替被代理的方法")//在被代理方法运行结束,就执行用@After修饰的方法
操作步骤和上面的@Before的几个例子一样
@Around :
@Around : 这方法里面,是真正的调用被代理的方法
写法 , 如 :
@Around("myMethod()")//这方法里面,是真正的调用被代理的方法,
public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("method around start-----1");
pjp.proceed();// 开始执行,被代理的方法 这才是真正的调用add()方法 并且,以后的代码,都默认添加在add()方法的方法体里面,追加的内容
System.out.println( "我会被默认融为被代理的方法中" );
}
}
@AfterReturning :
@AfterReturning("被代理的方法/代替被代理方法的方法")//当里面指定的方法返回值返回来之后,就执行用@AafterReturning修饰的方法
@AfterReturning("execution(public * com.jaovo.dao..*.*(..))")//这个是用截断某个包里面的所有方法,当这些方法返回值的时候,就执行此方法
@AfterReturning("myMethod()")//这个是绑定了代替被代理方法的方法,当被代理方法执行完成,返回值的时候,就执行用@AfterReturning修饰的方法
@AfterThrowing :
@AfterThrowing("被代理的方法/代替被代理方法的方法")//当里面指定的方法报异常之后,就执行用@AafterThrowing修饰的方法
@AfterReturning("execution(public * com.jaovo.dao..*.*(..))")//这个是用截断某个包里面的所有方法,当这些方法报异常的时候,就执行此方法
@AfterReturning("myMethod()")//这个是绑定了代替被代理方法的方法,当被代理方法报异常的时候,就执行用@AfterThrowing修饰的方法
@Transactional :
//设置回滚 写到某个方法的上面 就会对这个方法的执行,添加回滚(方法开始,会自动添加回滚点,如果报错,会直接跳回回滚点,就是方法开始执行的地方)
@Transactional(可以写两个值) :
1 propagation=Propagation.值 //这种是设置回滚(事务)的模式
Propagation.REQUIRED //这种,就相当于包含,由这个事务,一直跟着走,只要有一个地方报错,就立刻跳回调用这个方法的地方(就是添加事务设置回滚的地方)
Propagation.REQUIRES_NEW //这种是 , 执行一次方法,就添加一个新的事务(回滚点,谁的谁谁的都没有关系,有地方错了之后,那个事务错了,就跳回那个事务回滚点那个地方,并不用跳回第一个添加的那个回滚点)
Propagation.MANDATORY
Propagation.NESTED
Propagation.NOT_SUPPORTED //这个方法就不会支持事务,不会被添加回滚点(一般用这个的时候,都是和readOnly=true一起用的,为了数据安全,让那些不支持事务的方法,设置只读模式,就是不可以更改数据(不可以增删改) 只能查)
Propagation.SUPPORTS
2 readOnly = true //这种是设置为只读模式,不能进行增删改