Anton Arhipov wrote "Java Bytecode Fundamentals," basically illustrating what javac does and what kind of code the JVM takes as input. It's not exhaustive but it's a good start.
The developers who use Java for application development, usually do not need to be aware of the bytecode that is being executed in the VM. However, those developers who implement the state-of-the-art frameworks, compilers, or even Java tooling - may need to understand and may be even to use the bytecode directly. While special libraries (like ASM, cglib, Javassist) do help regarding bytecode manipulation, it is still important to understand the fundamentals in order to make the effective use of those tools.
I like how he puts the importance of this in context of AOP - this is the stuff AOP modifies, after all. It's crucial for understanding the tiny performance changes that modifying source code can make, and improves your skill at getting Java right.
The Java Virtual Machine Specification is still the final word on the matter, but reading one post will get you most of the understanding you need.